-
Notifications
You must be signed in to change notification settings - Fork 1
Getting started
First, install the gem
$ gem install rubylog
or, if you use bundler, add this line to your Gemfile
:
gem 'rubylog', '~>2.1'
Then require it
require 'rubylog'
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
# your code here
The basic building element of a Rubylog program is a structure. It consists of a functor name (which is a symbol) and some arguments (which can be any kind of object), and it represent a logical statement. For example, in the statement "John likes beer", "likes" would be the functor name 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 name between the first and the second argument. (Syntactically it is a method call with 'John'
as a receiver.) This is closer to the English word order.
To be able to use a functor you have to declare it, for the first argument's class.
module MyContext
extend Rubylog::Context
predicate_for String, ".likes()"
p 'John'.likes('beer') # outputs "John".likes("beer")
end
As you can see, structures have a programmer-readable string representation.
A predicate is a collection of known true statements. There are two type of statements: 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 method:
module MyContext
extend Rubylog::Context
predicate_for String, ".likes()"
'John'.likes!('beer')
end
You can assert a fact with the if
method of a structure:
module MyContext
extend Rubylog::Context
predicate_for String, ".likes() .drinks()"
'John'.drinks('beer').if 'John'.likes('beer')
end
You can ask yes-no questions if you want to know something from the database. You can use the question mark version of the functor or the true?
method.
module MyContext
extend Rubylog::Context
predicate_for String, ".likes()"
puts "Nay" if 'John'.likes?('beer') # gives no output
'John'.likes!('beer')
puts "Yes" if 'John'.likes?('beer') # outputs Yes
end
You can use variables instead of any data in structures. Any constant name that is not defined is treated as a variable.
module MyContext
extend Rubylog::Context
predicate_for String, ".likes()"
X.drinks(D).if X.likes(D)
end
A variable that starts with ANY...
is a so-called don't care variable. Its every appearance represents a different variable.
module MyContext
extend Rubylog::Context
predicate_for String, ".likes()"
'John'.likes!('beer')
puts ANY.likes?(ANY) # outputs true
end
You can use and
, or
, false
in statements just like you would use ,
, ;
, \+
in Prolog:
module MyContext
extend Rubylog::Context
predicate_for String, ".likes() .has() .thirsty .poison"
X.drinks(D).if X.has(D).and(X.likes(D).or X.thirsty).and D.poison.false
end
You can find solutions of a statement with the each method.
module MyContext
extend Rubylog::Context
predicate_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.
module MyContext
extend Rubylog::Context
predicate_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
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.
module MyContext
extend Rubylog::Context
predicate_for String, ".likes()"
'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