Skip to content
Bernát Kalló edited this page Aug 13, 2013 · 23 revisions

Installing

First, install the gem

$ gem install rubylog

or, if you use bundler, add this line to your Gemfile:

gem 'rubylog', '~>2.0'

Then require it

require 'rubylog'

Creating a context

You need a Rubylog context to use all the syntactic features.

module MyContext
  extend Rubylog::Context
  # your code here
end

When you use a console (irb/pry) and you need quick and dirty access to all the syntactic features, use

extend Rubylog::Context
Object.extend Rubylog::Context

Creating structures

The basic building element of a Rubylog program is a structure. It consists of a functor (which is a symbol) and some arguments (which can be any object), and it represent a logical statement. For example, in the statement "John likes beer", "likes" would be the functor and "John" and "beer" are the arguments.

While in Prolog, structures are written in prefix notation likes('John','beer'), in Rubylog they are written in infix notation 'John'.likes('beer'), with the functor between the first and the second argument. (Syntactically it is a method call with 'John' as a receiver.)

To be able to use a functor you have to declare it, for the first argument's class.

theory do
  functor_for String, :likes
  p 'John'.likes('beer')   # outputs "John".likes("beer")
end

As you can see, structures have a programmer-readable string representation.

Asserting facts and rules

The theory has an internal database of known true statements (which are called predicates). There are two type of predicates: facts and rules. A fact states that something is true, a rule states that something is true if some condition holds.

You can assert facts with the bang version of the functor or with assert:

theory do
  functor_for String, :likes
  'John'.likes!('beer')
  assert 'John'.likes('beer')
end

You can assert a fact with the if method of a structure, or with the assert method.

theory do
  functor_for String, :likes, :drinks
  'John'.drinks('beer').if 'John'.likes('beer')
  assert 'John'.drinks('beer'), 'John'.likes('beer')
end

Making queries

You can ask questions if you want to know something from the database. You can use the question mark version of the functor or the true? method.

theory do
  functor_for String, :likes
  puts "Yes" if 'John'.likes?('beer')   # gives no output
  'John'.likes!('beer')
  puts "Yes" if 'John'.likes?('beer')   # outputs Yes
end

Using variables

You can use variables instead of any data in structures. Any constant name that is not defined is treated as a variable.

theory do
  functor_for String, :likes
  X.drinks(D).if X.likes(D)
end

A variables that starts with ANY... is a so-called don't care variable. Even if two has the same name, they ar not the same.

theory do
  functor_for String, :likes
  'John'.likes!('beer')
  puts ANY.likes?(ANY)      # outputs true
end

Using logic

You can use and, or, false in statements just like you would use ,, ;, \+ in Prolog:

theory do
  functor_for String, :likes, :thirsty, :poison
  X.drinks(D).if X.has(D).and(X.likes(D).or X.thirsty).and D.poison.false
end

Finding each solution

You can find solutions of a statement with the each method.

theory do
  functor_for String, :likes
  'John'.likes! 'beer'
  'John'.likes! 'milk'
  'John'.likes(A).each do
    puts A
  end    # outputs beer and milk
end

You can use any of the well-known enumeration methods. However, the blocks don't get arguments.

theory do
  functor_for String, :likes
  'John'.likes! 'beer'
  'John'.likes! 'milk'

  'John'.likes(A).map{A}             # => ['beer','milk']
  'John'.likes(A).count              # => 2
  'John'.likes(A).any?{A =~ /ee/}    # => true
end

Including Ruby code

You have several means to include Ruby code within your Rubylog code. One of them is the use of enumerator methods you have seen above. In the following code, every code between {} is native Ruby code.

theory do
  'John'.likes(A).if proc{ A =~ /beer/ }                # a proc can be used instead of a structure
  'John'.likes(A).if { A =~ /beer/ }                    # this is the same
  'John'.likes(A).if A.is(proc{ get_favorite_drink() }) # .is() can receive a proc which can return a value
  'John'.likes(A).if A.is{ get_favorite_drink() }       # this is the same
end
Clone this wiki locally