porolog
<img src=“repository-images.githubusercontent.com/131847563/b3754100-636a-11e9-995b-20d409b992c9” width=“240” height=“120” align=“right” />
Plain Old Ruby Objects Prolog (WORK IN PROGRESS)
Introduction
porolog
is a Prolog implementation using plain old Ruby objects with the aim that logic queries can be called within a regular Ruby program. The goal was not to implement a Prolog interpreter that is just implement in Ruby, but rather that a logic engine could be embedded in a larger program.
The need that this gem aims to meet is to have a Ruby program interact with a Prolog program using native Ruby objects (POROs); hence the name Porolog. The goal was to implement a minimal logic engine in the style of Prolog where Ruby objects could be passed in and Ruby objects were passed back.
Dependencies
The aim of porolog
is to provide a logic engine with a minimal footprint. The only extra dependency is Yard for documentation.
Installation
gem install porolog
Usage
porolog
is used by:
-
requiring the library within a Ruby program
-
defining facts and rules
-
solving goals
It is entirely possible to create a Ruby program that is effectively just a Prolog program.
Basic Usage
Using porolog
involves creating logic from facts and rules. An example, of the most basic usage uses just facts.
require 'porolog'
prime = Porolog::Predicate.new :prime
prime.(2).fact!
prime.(3).fact!
prime.(5).fact!
prime.(7).fact!
solutions = prime.(:X).solve
solutions.each do |solution|
puts "#{solution[:X]} is prime"
end
Common Usage
Common usage is expected to be including Porolog in a class and encapsulating the engine defined.
require 'porolog'
include Porolog
class Numbers
Predicate.scope self
predicate :prime
prime(2).fact!
prime(3).fact!
prime(5).fact!
prime(7).fact!
def show_primes
solutions = prime(:X).solve
solutions.each do |solution|
puts "#{solution[:X]} is prime"
end
end
def primes
prime(:X).solve_for(:X)
end
end
numbers = Numbers.new
numbers.show_primes
puts numbers.primes.inspect
Scope and Predicate Usage
A Predicate represents a Prolog predicate. They form the basis for rules and queries.
The Scope class enables you to have multiple logic programs embedded in the same Ruby program. A Scope object defines a scope for the predicates of a logic programme.
require 'porolog'
# -- Prime Numbers Predicate --
prime = prime1 = Porolog::Predicate.new :prime, :numbers
prime.(2).fact!
prime.(3).fact!
prime.(5).fact!
prime.(7).fact!
prime.(11).fact!
# -- Pump Predicate --
prime = prime2 = Porolog::Predicate.new :prime, :pumps
prime.('pump A').fact!
prime.('pump B').fact!
prime.('pump C').fact!
prime.('pump D').fact!
# -- Assertions --
assert_equal [:default,:numbers,:pumps], Scope.scopes
assert_scope Porolog::Scope[:default], :default, []
assert_scope Porolog::Scope[:numbers], :first, [prime1]
assert_scope Porolog::Scope[:pumps], :second, [prime2]
assert_equal :prime, prime1.name
assert_equal :prime, prime2.name
solutions = [
{ X: 2 },
{ X: 3 },
{ X: 5 },
{ X: 7 },
{ X: 11 },
]
assert_equal solutions, prime1.(:X).solve
solutions = [
{ X: 'pump A' },
{ X: 'pump B' },
{ X: 'pump C' },
{ X: 'pump D' },
]
assert_equal solutions, prime2.(:X).solve
Testing
rake test
or
rake core_ext_test
rake porolog_test
rake scope_test
rake predicate_test
rake arguments_test
rake rule_test
rake goal_test
rake variable_test
rake value_test
rake tail_test
rake instantiation_test
Author
Luis Esteban MSc MTeach