rubylog 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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!
|