rubylog 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +64 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +96 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/examples/4queens.rb +10 -0
- data/examples/calculation.rb +12 -0
- data/examples/concepts.rb +46 -0
- data/examples/factorial.rb +16 -0
- data/examples/fp.rb +56 -0
- data/examples/hello.rb +9 -0
- data/examples/historia_de_espana.rb +31 -0
- data/examples/idea.rb +143 -0
- data/examples/lists.rb +5 -0
- data/examples/mechanika.rb +409 -0
- data/examples/parse.rb +15 -0
- data/examples/theory.rb +20 -0
- data/lib/array.rb +24 -0
- data/lib/class.rb +11 -0
- data/lib/method.rb +4 -0
- data/lib/object.rb +5 -0
- data/lib/proc.rb +4 -0
- data/lib/rubylog/builtins.rb +193 -0
- data/lib/rubylog/callable.rb +20 -0
- data/lib/rubylog/clause.rb +113 -0
- data/lib/rubylog/composite_term.rb +38 -0
- data/lib/rubylog/dsl/constants.rb +15 -0
- data/lib/rubylog/dsl/first_order_functors.rb +9 -0
- data/lib/rubylog/dsl/global_functors.rb +3 -0
- data/lib/rubylog/dsl/second_order_functors.rb +8 -0
- data/lib/rubylog/dsl.rb +52 -0
- data/lib/rubylog/errors.rb +18 -0
- data/lib/rubylog/internal_helpers.rb +16 -0
- data/lib/rubylog/predicate.rb +34 -0
- data/lib/rubylog/proc_method_additions.rb +69 -0
- data/lib/rubylog/term.rb +20 -0
- data/lib/rubylog/theory.rb +133 -0
- data/lib/rubylog/unifiable.rb +19 -0
- data/lib/rubylog/variable.rb +97 -0
- data/lib/rubylog.rb +39 -0
- data/lib/symbol.rb +35 -0
- data/rubylog.gemspec +187 -0
- data/script/inriasuite2spec +0 -0
- data/script/inriasuite2spec.pl +22 -0
- data/spec/bartak_guide_spec.rb +91 -0
- data/spec/inriasuite/README +122 -0
- data/spec/inriasuite/abolish +18 -0
- data/spec/inriasuite/and +9 -0
- data/spec/inriasuite/arg +32 -0
- data/spec/inriasuite/arith_diff +10 -0
- data/spec/inriasuite/arith_eq +10 -0
- data/spec/inriasuite/arith_gt +10 -0
- data/spec/inriasuite/arith_gt= +10 -0
- data/spec/inriasuite/arith_lt +10 -0
- data/spec/inriasuite/arith_lt= +10 -0
- data/spec/inriasuite/asserta +18 -0
- data/spec/inriasuite/assertz +16 -0
- data/spec/inriasuite/atom +12 -0
- data/spec/inriasuite/atom_chars +19 -0
- data/spec/inriasuite/atom_codes +15 -0
- data/spec/inriasuite/atom_concat +19 -0
- data/spec/inriasuite/atom_length +12 -0
- data/spec/inriasuite/atomic +11 -0
- data/spec/inriasuite/bagof +31 -0
- data/spec/inriasuite/call +19 -0
- data/spec/inriasuite/catch-and-throw +16 -0
- data/spec/inriasuite/char_code +13 -0
- data/spec/inriasuite/clause +16 -0
- data/spec/inriasuite/compound +12 -0
- data/spec/inriasuite/copy_term +25 -0
- data/spec/inriasuite/current_input +5 -0
- data/spec/inriasuite/current_output +5 -0
- data/spec/inriasuite/current_predicate +16 -0
- data/spec/inriasuite/current_prolog_flag +12 -0
- data/spec/inriasuite/cut +9 -0
- data/spec/inriasuite/fail +15 -0
- data/spec/inriasuite/file_manip +8 -0
- data/spec/inriasuite/findall +22 -0
- data/spec/inriasuite/float +10 -0
- data/spec/inriasuite/functor +41 -0
- data/spec/inriasuite/functor-bis +41 -0
- data/spec/inriasuite/halt +7 -0
- data/spec/inriasuite/if-then +10 -0
- data/spec/inriasuite/if-then-else +12 -0
- data/spec/inriasuite/inriasuite.obp +0 -0
- data/spec/inriasuite/inriasuite.pl +836 -0
- data/spec/inriasuite/integer +10 -0
- data/spec/inriasuite/is +11 -0
- data/spec/inriasuite/junk +0 -0
- data/spec/inriasuite/nonvar +11 -0
- data/spec/inriasuite/not_provable +12 -0
- data/spec/inriasuite/not_unify +15 -0
- data/spec/inriasuite/number +10 -0
- data/spec/inriasuite/number_chars +22 -0
- data/spec/inriasuite/number_codes +19 -0
- data/spec/inriasuite/once +11 -0
- data/spec/inriasuite/or +9 -0
- data/spec/inriasuite/repeat +5 -0
- data/spec/inriasuite/retract +10 -0
- data/spec/inriasuite/set_prolog_flag +21 -0
- data/spec/inriasuite/setof +36 -0
- data/spec/inriasuite/sub_atom +30 -0
- data/spec/inriasuite/t +1 -0
- data/spec/inriasuite/t_foo.pl +4 -0
- data/spec/inriasuite/term_diff +13 -0
- data/spec/inriasuite/term_eq +12 -0
- data/spec/inriasuite/term_gt +12 -0
- data/spec/inriasuite/term_gt= +12 -0
- data/spec/inriasuite/term_lt +12 -0
- data/spec/inriasuite/term_lt= +12 -0
- data/spec/inriasuite/true +7 -0
- data/spec/inriasuite/unify +18 -0
- data/spec/inriasuite.rb +20 -0
- data/spec/recursion_spec.rb +18 -0
- data/spec/rubylog/builtins/splits_to.rb +18 -0
- data/spec/rubylog/clause_spec.rb +81 -0
- data/spec/rubylog/variable_spec.rb +25 -0
- data/spec/rubylog_spec.rb +914 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/theory_spec.rb +1 -0
- metadata +339 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
module Rubylog
|
2
|
+
class Clause
|
3
|
+
|
4
|
+
# data structure
|
5
|
+
attr_reader :functor, :args
|
6
|
+
def initialize functor, *args
|
7
|
+
@functor = functor
|
8
|
+
@args = args.freeze
|
9
|
+
@arity = args.count
|
10
|
+
end
|
11
|
+
|
12
|
+
def [] i
|
13
|
+
@args[i]
|
14
|
+
end
|
15
|
+
|
16
|
+
def == other
|
17
|
+
other.instance_of? Clause and
|
18
|
+
@functor == other.functor and @args == other.args
|
19
|
+
end
|
20
|
+
alias eql? ==
|
21
|
+
|
22
|
+
def hash
|
23
|
+
@functor.hash ^ @args.hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
"#{@args[0].inspect}.#{@functor}#{
|
28
|
+
"(#{@args[1..-1].inspect[1..-2]})" if @args.count>1
|
29
|
+
}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
inspect
|
34
|
+
end
|
35
|
+
|
36
|
+
def arity
|
37
|
+
@arity
|
38
|
+
end
|
39
|
+
|
40
|
+
def desc
|
41
|
+
[@functor, @arity]
|
42
|
+
end
|
43
|
+
|
44
|
+
# assertion routines
|
45
|
+
def if body=nil, &block
|
46
|
+
Rubylog.theory.assert self, body || block
|
47
|
+
end
|
48
|
+
|
49
|
+
def unless body=nil, &block
|
50
|
+
Rubylog.theory.assert self, Clause.new(:is_false, body || block)
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
# Callable methods
|
56
|
+
include Rubylog::Callable
|
57
|
+
|
58
|
+
def prove
|
59
|
+
Rubylog.theory.trace 1, self, InternalHelpers.vars_hash_of(self)
|
60
|
+
predicate = Rubylog.theory[@functor][@arity]
|
61
|
+
raise ExistenceError, desc.inspect if not predicate
|
62
|
+
predicate.call(*@args) { yield }
|
63
|
+
Rubylog.theory.trace -1
|
64
|
+
end
|
65
|
+
|
66
|
+
# enumerable methods
|
67
|
+
include Enumerable
|
68
|
+
alias each solve
|
69
|
+
|
70
|
+
# Unifiable methods
|
71
|
+
include Rubylog::Unifiable
|
72
|
+
def rubylog_unify other
|
73
|
+
return super{yield} unless other.instance_of? self.class
|
74
|
+
return unless other.functor == @functor
|
75
|
+
return unless @arity == other.arity
|
76
|
+
@args.rubylog_unify(other.args) { yield }
|
77
|
+
end
|
78
|
+
|
79
|
+
attr_reader :rubylog_variables
|
80
|
+
|
81
|
+
# CompositeTerm methods
|
82
|
+
include Rubylog::CompositeTerm
|
83
|
+
def rubylog_clone &block
|
84
|
+
block.call Clause.new @functor,
|
85
|
+
*@args.map{|a|a.rubylog_clone &block}
|
86
|
+
end
|
87
|
+
|
88
|
+
# Second-order functors (:is_false, :and, :or, :then)
|
89
|
+
include Rubylog::DSL::SecondOrderFunctors
|
90
|
+
|
91
|
+
# convenience methods
|
92
|
+
def solutions
|
93
|
+
goal = rubylog_compile_variables
|
94
|
+
goal.variable_hashes_without_compile.map do |hash|
|
95
|
+
goal.rubylog_clone {|i| hash[i] || i }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def variable_hashes
|
100
|
+
rubylog_compile_variables.variable_hashes_without_compile
|
101
|
+
end
|
102
|
+
|
103
|
+
protected
|
104
|
+
|
105
|
+
def variable_hashes_without_compile
|
106
|
+
variables = rubylog_variables
|
107
|
+
map do |*values|
|
108
|
+
Hash[variables.zip values]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Rubylog
|
2
|
+
module CompositeTerm
|
3
|
+
def rubylog_compile_variables
|
4
|
+
vars = []; vars_by_name = {}
|
5
|
+
rubylog_clone do |i|
|
6
|
+
if i.is_a? Rubylog::Variable
|
7
|
+
if i.dont_care?
|
8
|
+
i = i.dup
|
9
|
+
else
|
10
|
+
i = vars_by_name[i.name] || begin
|
11
|
+
r = i.dup
|
12
|
+
vars << r
|
13
|
+
vars_by_name[i.name] = r
|
14
|
+
end
|
15
|
+
end
|
16
|
+
elsif i.is_a? Rubylog::CompositeTerm
|
17
|
+
i.instance_variable_set :"@rubylog_variables", vars
|
18
|
+
end
|
19
|
+
i
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def rubylog_deep_dereference
|
24
|
+
rubylog_clone do |i|
|
25
|
+
i.rubylog_deep_dereference
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :rubylog_variables
|
30
|
+
|
31
|
+
|
32
|
+
# should return a deep copy of the term, atomic terms treated as
|
33
|
+
# leaves, with &block called post-order
|
34
|
+
#def rubylog_clone &block
|
35
|
+
#block.call self.class.new attr1.rubylog_clone &block
|
36
|
+
#end
|
37
|
+
end
|
38
|
+
end
|
data/lib/rubylog/dsl.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Rubylog::DSL
|
2
|
+
def self.add_first_order_functor *fs
|
3
|
+
add_functors_to FirstOrderFunctors, *fs
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.add_second_order_functor *fs
|
7
|
+
add_functors_to SecondOrderFunctors, *fs
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.add_functors_to class_or_module, *functors
|
11
|
+
functors.each do |f|
|
12
|
+
m = functor_module(f)
|
13
|
+
class_or_module.send :include, m
|
14
|
+
Rubylog::Variable.send :include, m
|
15
|
+
add_global_functor f
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
@functor_modules ||= {}
|
20
|
+
|
21
|
+
def self.functor_module f
|
22
|
+
@functor_modules[f] ||= Module.new do
|
23
|
+
define_method f do |*args, &block|
|
24
|
+
args << block if block
|
25
|
+
Rubylog::Clause.new f, self, *args
|
26
|
+
end
|
27
|
+
|
28
|
+
f_bang = :"#{f}!"
|
29
|
+
define_method f_bang do |*args, &block|
|
30
|
+
args << block if block
|
31
|
+
Rubylog.theory.assert Rubylog::Clause.new(f, self, *args), :true
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
f_qmark = :"#{f}?"
|
36
|
+
define_method f_qmark do |*args, &block|
|
37
|
+
args << block if block
|
38
|
+
Rubylog.theory.true? Rubylog::Clause.new(f, self, *args)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def self.add_global_functor f
|
46
|
+
GlobalFunctors.send :define_method, f do |*args, &block|
|
47
|
+
args << block if block
|
48
|
+
Rubylog::Clause.new f, *args
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rubylog
|
2
|
+
class RubylogError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class DiscontinuousPredicateError < RubylogError
|
6
|
+
end
|
7
|
+
|
8
|
+
class BuiltinPredicateError < RubylogError
|
9
|
+
end
|
10
|
+
|
11
|
+
class ExistenceError < RubylogError
|
12
|
+
end
|
13
|
+
|
14
|
+
class InvalidStateError < RubylogError
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rubylog::InternalHelpers
|
2
|
+
class << self
|
3
|
+
def non_empty_list
|
4
|
+
l = []
|
5
|
+
while true do
|
6
|
+
l << Rubylog::Variable.new(:_)
|
7
|
+
yield l
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def vars_hash_of o
|
12
|
+
vars = o.rubylog_variables
|
13
|
+
Hash[vars.zip(vars.map{|v|v.value})]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
module Rubylog
|
3
|
+
class Predicate < Array
|
4
|
+
# accepts the *args of the called clause
|
5
|
+
def call *args
|
6
|
+
begin
|
7
|
+
each do |rule|
|
8
|
+
rule = rule.rubylog_compile_variables
|
9
|
+
head, body = rule[0], rule[1]
|
10
|
+
head.args.rubylog_unify(args) {
|
11
|
+
Rubylog.theory.trace 1, head, InternalHelpers.vars_hash_of(head)
|
12
|
+
body.prove {
|
13
|
+
yield
|
14
|
+
}
|
15
|
+
Rubylog.theory.trace -1
|
16
|
+
}
|
17
|
+
end
|
18
|
+
rescue Cut
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def discontinuous!
|
23
|
+
@discontinuous = true
|
24
|
+
end
|
25
|
+
|
26
|
+
def discontinuous?
|
27
|
+
@discontinuous
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Rubylog
|
2
|
+
module ProcMethodAdditions
|
3
|
+
|
4
|
+
# Procs and methods are used three ways.
|
5
|
+
#
|
6
|
+
# Firstly, as a predicate. A predicate is an object that responds to #call,
|
7
|
+
# and yields if and the number of times the represented predicate is
|
8
|
+
# provable. Built-in predicates are implemented this way.
|
9
|
+
# Example (definition of a new built-in twice):
|
10
|
+
# def self.twice; yield; yield; end
|
11
|
+
# theory[:twice][0] = method :twice
|
12
|
+
#
|
13
|
+
# Secondly, as a callable term. A callable term is a term that responds to
|
14
|
+
# #prove, and yields if and the number of times the represented predicate is
|
15
|
+
# provable. This implementation calls the proc/method with the variables from
|
16
|
+
# the sentence passed as arguments, and yields once iff the proc/method
|
17
|
+
# returned true. This permits the use of block instead of a callable term.
|
18
|
+
# Examples:
|
19
|
+
# :good_age(A).if {|a|a >= 13}
|
20
|
+
#
|
21
|
+
# :greet(N).if female(N).and {|n| puts "Hello, Ms. #{n}"; true }
|
22
|
+
# :greet(N).if male(N).and {|n| puts "Hello, Mr. #{n}"; true }
|
23
|
+
#
|
24
|
+
# Thirdly, as a function. A function is a term that responds to
|
25
|
+
# #rubylog_resolve_function and does something else than returning self.
|
26
|
+
# Built-in predicates with two or more arguments, that require a not
|
27
|
+
# necessarily callable term as their last argument should call
|
28
|
+
# rubylog_resolve_function on this argument if it responds to it. This
|
29
|
+
# permits users to use a block instead of the last argument. Examples:
|
30
|
+
# :greeting(N,G).if female(N).then G.is {|n| "Hello, Ms. #{n}" }
|
31
|
+
# :greeting(N,G).if male(N).then G.is {|n| "Hello, Mr. #{n}" }
|
32
|
+
#
|
33
|
+
|
34
|
+
|
35
|
+
def self.included class_or_module
|
36
|
+
class_or_module.send :include, Rubylog::Callable
|
37
|
+
|
38
|
+
# procs and methods are composite terms, just to simply get
|
39
|
+
# access to variables
|
40
|
+
class_or_module.send :include, Rubylog::CompositeTerm
|
41
|
+
end
|
42
|
+
|
43
|
+
# Callable methods
|
44
|
+
def prove
|
45
|
+
yield if call_with_rubylog_variables
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def call_with_rubylog_variables
|
50
|
+
raise Rubylog::InvalidStateError, "variables not available" if not @rubylog_variables
|
51
|
+
if arity == -1
|
52
|
+
call *@rubylog_variables.map{|v|v.value}
|
53
|
+
else
|
54
|
+
call *@rubylog_variables[0...arity].map{|v|v.value}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Term methods
|
59
|
+
def rubylog_resolve_function
|
60
|
+
call_with_rubylog_variables
|
61
|
+
end
|
62
|
+
|
63
|
+
# CompositeTerm methods
|
64
|
+
def rubylog_clone
|
65
|
+
yield dup
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
data/lib/rubylog/term.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
module Rubylog
|
2
|
+
class Cut < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
def self.theory
|
6
|
+
Thread.current[:rubylog_theory]
|
7
|
+
end
|
8
|
+
|
9
|
+
class Theory
|
10
|
+
include Rubylog::DSL::Constants
|
11
|
+
|
12
|
+
def self.new!
|
13
|
+
Thread.current[:rubylog_theory] = new
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@database = Hash.new{|h,k| h[k] =
|
18
|
+
{}
|
19
|
+
}.merge! BUILTINS
|
20
|
+
@variable_bindings = []
|
21
|
+
@public_interface = Module.new
|
22
|
+
@trace = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def [] *args
|
26
|
+
database[*args]
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear
|
30
|
+
initialize
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# directives
|
35
|
+
#
|
36
|
+
def predicate *descs
|
37
|
+
descs.each do |desc|
|
38
|
+
create_predicate *desc
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def discontinuous *descs
|
43
|
+
descs.each do |desc|
|
44
|
+
create_predicate(*desc).discontinuous!
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :database
|
49
|
+
attr_reader :public_interface
|
50
|
+
|
51
|
+
|
52
|
+
# predicates
|
53
|
+
|
54
|
+
def assert head, body=:true
|
55
|
+
functor, arity = head.functor, head.arity
|
56
|
+
predicate = database[functor][arity]
|
57
|
+
if predicate
|
58
|
+
check_assertable predicate, head, body
|
59
|
+
else
|
60
|
+
predicate = create_predicate functor, arity
|
61
|
+
end
|
62
|
+
predicate << Clause.new(:-, head, body)
|
63
|
+
@last_predicate = predicate
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def solve goal
|
68
|
+
goal = goal.rubylog_compile_variables
|
69
|
+
goal.prove { yield(*goal.rubylog_variables.map{|v|v.value}) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def true? goal
|
73
|
+
goal = goal.rubylog_compile_variables
|
74
|
+
goal.prove { return true }
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
# debugging
|
79
|
+
#
|
80
|
+
#
|
81
|
+
def trace?
|
82
|
+
@trace
|
83
|
+
end
|
84
|
+
|
85
|
+
def trace!
|
86
|
+
@trace=true
|
87
|
+
@trace_levels = 0
|
88
|
+
end
|
89
|
+
|
90
|
+
def trace level, *args
|
91
|
+
return unless @trace
|
92
|
+
@trace_levels += level
|
93
|
+
puts " "*level + args.map{|a|a.inspect}.join(" ") if not args.empty?
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
|
99
|
+
def check_assertable predicate, head, body
|
100
|
+
raise BuiltinPredicateError, head.desc.inspect, caller[2..-1] unless predicate.is_a? Predicate
|
101
|
+
raise DiscontinuousPredicateError, head.desc.inspect, caller[2..-1] if not predicate.empty? and predicate != @last_predicate and not predicate.discontinuous?
|
102
|
+
end
|
103
|
+
|
104
|
+
def create_predicate functor, arity
|
105
|
+
DSL.add_functors_to @public_interface, functor
|
106
|
+
database[functor][arity] = Predicate.new
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
#class << self
|
111
|
+
#def private *args
|
112
|
+
#if args.empty?
|
113
|
+
#@scope = :private
|
114
|
+
#else
|
115
|
+
#end
|
116
|
+
#end
|
117
|
+
#def protected *args
|
118
|
+
#if args.empty?
|
119
|
+
#@scope = :protected
|
120
|
+
#else
|
121
|
+
#end
|
122
|
+
#end
|
123
|
+
#end
|
124
|
+
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rubylog
|
2
|
+
module Unifiable
|
3
|
+
def rubylog_unify other
|
4
|
+
if other.kind_of? Rubylog::Variable
|
5
|
+
other.rubylog_unify(self) do yield end
|
6
|
+
else
|
7
|
+
yield if self == other
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def rubylog_dereference
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def rubylog_deep_dereference
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Rubylog
|
2
|
+
class Variable
|
3
|
+
|
4
|
+
# data structure
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
def initialize name
|
8
|
+
@name = name
|
9
|
+
@assigned = false
|
10
|
+
@dont_care = !!(name.to_s =~ /^(?:ANY|_)/)
|
11
|
+
end
|
12
|
+
|
13
|
+
def assigned?
|
14
|
+
@assigned
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
@name.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
@name.to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
def == other
|
26
|
+
Variable === other and @name == other.name
|
27
|
+
end
|
28
|
+
|
29
|
+
def eql? other
|
30
|
+
Variable === other and @name == other.name
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
def value
|
36
|
+
return nil if (val = rubylog_dereference).kind_of? Variable
|
37
|
+
val
|
38
|
+
end
|
39
|
+
|
40
|
+
def dont_care?
|
41
|
+
@dont_care
|
42
|
+
end
|
43
|
+
|
44
|
+
# Term methods
|
45
|
+
|
46
|
+
# rubylog_clone stays as is
|
47
|
+
|
48
|
+
def rubylog_variables
|
49
|
+
[self]
|
50
|
+
end
|
51
|
+
|
52
|
+
# Unifiable methods
|
53
|
+
include Unifiable
|
54
|
+
|
55
|
+
def rubylog_unify other
|
56
|
+
if @assigned
|
57
|
+
rubylog_dereference.rubylog_unify(other) do yield end
|
58
|
+
else
|
59
|
+
begin
|
60
|
+
@assigned = true; @value = other
|
61
|
+
yield
|
62
|
+
ensure
|
63
|
+
@assigned = false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def rubylog_dereference
|
69
|
+
if @assigned
|
70
|
+
@value.rubylog_dereference
|
71
|
+
else
|
72
|
+
self
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def rubylog_deep_dereference
|
77
|
+
if @assigned
|
78
|
+
@value.rubylog_deep_dereference
|
79
|
+
else
|
80
|
+
self
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Callable methods
|
85
|
+
include Callable
|
86
|
+
|
87
|
+
def prove
|
88
|
+
# XXX not tested
|
89
|
+
v = value
|
90
|
+
raise InstantiationError if v.nil?
|
91
|
+
v.prove{yield}
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
end
|
data/lib/rubylog.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# rubylog.rb -- Prolog workalike for Ruby
|
2
|
+
# github.com/cie/rubylog
|
3
|
+
|
4
|
+
# rtl
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
# interfaces
|
8
|
+
require 'rubylog/term.rb'
|
9
|
+
require 'rubylog/callable.rb'
|
10
|
+
require 'rubylog/unifiable.rb'
|
11
|
+
require 'rubylog/composite_term.rb'
|
12
|
+
|
13
|
+
# helpers
|
14
|
+
require 'rubylog/dsl.rb'
|
15
|
+
require 'rubylog/dsl/constants.rb'
|
16
|
+
require 'rubylog/dsl/first_order_functors.rb'
|
17
|
+
require 'rubylog/dsl/global_functors.rb'
|
18
|
+
require 'rubylog/dsl/second_order_functors.rb'
|
19
|
+
require 'rubylog/proc_method_additions.rb'
|
20
|
+
require 'rubylog/internal_helpers.rb'
|
21
|
+
|
22
|
+
# classes
|
23
|
+
require 'rubylog/errors.rb'
|
24
|
+
require 'rubylog/predicate.rb'
|
25
|
+
require 'rubylog/theory.rb'
|
26
|
+
require 'rubylog/variable.rb'
|
27
|
+
|
28
|
+
# builtins
|
29
|
+
require 'rubylog/builtins.rb'
|
30
|
+
|
31
|
+
require 'rubylog/clause.rb'
|
32
|
+
require 'array.rb'
|
33
|
+
require 'symbol.rb'
|
34
|
+
require 'proc.rb'
|
35
|
+
require 'object.rb'
|
36
|
+
require 'class.rb'
|
37
|
+
require 'method.rb'
|
38
|
+
|
39
|
+
Rubylog::Theory.new!
|