rubylog 1.0.0 → 2.0pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -12
- data/Gemfile.lock +22 -48
- data/README.rdoc +38 -38
- data/README.rdoc.orig +284 -0
- data/RELEASE_NOTES.rdoc +51 -0
- data/Rakefile +14 -18
- data/TODO.txt +0 -0
- data/VERSION +1 -1
- data/examples/a_plus_b.rb +6 -0
- data/examples/checkmate.rb +88 -0
- data/examples/combination.rb +17 -0
- data/examples/dcg.rb +3 -2
- data/examples/dcg2.rb +2 -2
- data/{logic → examples}/directory_structure_logic.rb +3 -5
- data/examples/dirlist.rb +4 -0
- data/examples/divisors.rb +6 -0
- data/examples/enumerators.rb +3 -3
- data/examples/factorial.rb +2 -3
- data/examples/file_search.rb +14 -0
- data/examples/hanoi.rb +4 -5
- data/examples/hello.rb +6 -4
- data/examples/mice.rb +92 -0
- data/examples/mice2.rb +19 -0
- data/examples/n_queens.rb +32 -0
- data/examples/object_oriented.rb +14 -0
- data/examples/palindrome_detection.rb +18 -0
- data/examples/parsing.rb +6 -4
- data/examples/permutation.rb +12 -0
- data/examples/prefix.rb +13 -0
- data/examples/primality_by_division.rb +22 -0
- data/examples/primitives.rb +10 -8
- data/examples/sieve_of_eratosthenes.rb +14 -0
- data/examples/string_interpolation.rb +4 -0
- data/examples/sudoku.rb +52 -0
- data/examples/tracing.rb +19 -0
- data/lib/rspec/rubylog.rb +29 -0
- data/lib/rubylog/assertable.rb +24 -0
- data/lib/rubylog/builtins/arithmetics.rb +63 -0
- data/lib/rubylog/builtins/assumption.rb +71 -0
- data/lib/rubylog/builtins/ensure.rb +13 -0
- data/lib/rubylog/builtins/file_system.rb +30 -8
- data/lib/rubylog/builtins/logic.rb +69 -38
- data/lib/rubylog/builtins/reflection.rb +35 -50
- data/lib/rubylog/builtins/term.rb +15 -17
- data/lib/rubylog/builtins.rb +11 -0
- data/lib/rubylog/clause.rb +19 -0
- data/lib/rubylog/{interfaces/composite_term.rb → compound_term.rb} +3 -3
- data/lib/rubylog/context.rb +24 -0
- data/lib/rubylog/context_creation.rb +71 -0
- data/lib/rubylog/context_modules/checks.rb +35 -0
- data/lib/rubylog/context_modules/demonstration.rb +16 -0
- data/lib/rubylog/context_modules/predicates.rb +86 -0
- data/lib/rubylog/context_modules/primitives.rb +18 -0
- data/lib/rubylog/context_modules/thats.rb +13 -0
- data/lib/rubylog/default_context.rb +9 -0
- data/lib/rubylog/dsl/array_splat.rb +11 -3
- data/lib/rubylog/dsl/primitives.rb +24 -12
- data/lib/rubylog/dsl/thats.rb +6 -0
- data/lib/rubylog/dsl/variables.rb +56 -21
- data/lib/rubylog/errors.rb +26 -15
- data/lib/rubylog/mixins/array.rb +95 -62
- data/lib/rubylog/mixins/kernel.rb +3 -2
- data/lib/rubylog/mixins/method.rb +0 -1
- data/lib/rubylog/mixins/object.rb +2 -1
- data/lib/rubylog/mixins/proc.rb +9 -12
- data/lib/rubylog/mixins/string.rb +15 -23
- data/lib/rubylog/mixins/symbol.rb +7 -24
- data/lib/rubylog/nullary_predicates.rb +3 -0
- data/lib/rubylog/predicate.rb +53 -0
- data/lib/rubylog/primitive.rb +15 -0
- data/lib/rubylog/procedure.rb +42 -0
- data/lib/rubylog/rule.rb +24 -0
- data/lib/rubylog/structure.rb +19 -38
- data/lib/rubylog/{interfaces/term.rb → term.rb} +2 -7
- data/lib/rubylog/tracing.rb +75 -0
- data/lib/rubylog/variable.rb +31 -12
- data/lib/rubylog.rb +36 -32
- data/rubylog.gemspec +92 -84
- data/spec/inriasuite_spec.rb +906 -9
- data/spec/integration/custom_classes_spec.rb +61 -0
- data/spec/integration/dsl_spec.rb +38 -0
- data/spec/integration/recursion_spec.rb +14 -0
- data/spec/integration/theory_as_module_spec.rb +20 -0
- data/spec/integration/theory_as_module_with_include_spec.rb +14 -0
- data/spec/rspec/rubylog_spec.rb +75 -0
- data/spec/rubylog/assertable_spec.rb +111 -0
- data/spec/rubylog/builtins/arithmetics_spec.rb +94 -0
- data/spec/rubylog/builtins/assumption_spec.rb +70 -0
- data/spec/rubylog/builtins/ensure_spec.rb +8 -0
- data/spec/rubylog/builtins/file_system_spec.rb +40 -0
- data/spec/rubylog/builtins/logic_spec.rb +340 -0
- data/spec/rubylog/builtins/reflection_spec.rb +43 -0
- data/spec/rubylog/builtins/term_spec.rb +85 -0
- data/spec/rubylog/context_modules/demonstration_spec.rb +132 -0
- data/spec/rubylog/context_modules/predicates_spec.rb +57 -0
- data/spec/rubylog/context_modules/thats_spec.rb +94 -0
- data/spec/rubylog/dsl/array_splat_spec.rb +15 -0
- data/spec/rubylog/dsl/primitives_spec.rb +43 -0
- data/spec/rubylog/errors_spec.rb +18 -0
- data/spec/{unification_spec.rb → rubylog/interfaces/term_spec.rb} +8 -9
- data/spec/rubylog/mixins/array_spec.rb +80 -0
- data/spec/rubylog/mixins/composite_term_spec.rb +66 -0
- data/spec/rubylog/mixins/proc_spec.rb +59 -0
- data/spec/rubylog/mixins/string_spec.rb +48 -0
- data/spec/rubylog/mixins/symbol_spec.rb +9 -0
- data/spec/{clause_spec.rb → rubylog/structure_spec.rb} +16 -15
- data/spec/rubylog/term_spec.rb +7 -0
- data/spec/rubylog/tracing_spec.input +27 -0
- data/spec/rubylog/tracing_spec.rb +44 -0
- data/spec/rubylog/variable_spec.rb +279 -0
- data/spec/spec_helper.rb +1 -0
- data/vimrc +11 -0
- metadata +103 -123
- data/README.hu.rb +0 -58
- data/bin/rubylog +0 -18
- data/examples/theory.rb +0 -32
- data/lib/rubylog/builtins/default.rb +0 -10
- data/lib/rubylog/dsl.rb +0 -70
- data/lib/rubylog/interfaces/assertable.rb +0 -16
- data/lib/rubylog/interfaces/callable.rb +0 -18
- data/lib/rubylog/interfaces/predicate.rb +0 -8
- data/lib/rubylog/interfaces/procedure.rb +0 -60
- data/lib/rubylog/mixins/class.rb +0 -11
- data/lib/rubylog/simple_procedure.rb +0 -8
- data/lib/rubylog/theory.rb +0 -422
- data/logic/builtins/file_system_logic.rb +0 -23
- data/logic/builtins/reflection_logic.rb +0 -40
- data/logic/dereference_logic.rb +0 -23
- data/logic/dsl_logic.rb +0 -29
- data/logic/errors_logic.rb +0 -9
- data/logic/guard_logic.rb +0 -115
- data/logic/list_logic.rb +0 -55
- data/logic/map_logic.rb +0 -15
- data/logic/multitheory.rb +0 -23
- data/logic/recursion_logic.rb +0 -12
- data/logic/string_logic.rb +0 -41
- data/logic/thats_logic.rb +0 -51
- data/logic/variable_logic.rb +0 -24
- data/spec/bartak_guide_spec.rb +0 -86
- data/spec/builtins/all_spec.rb +0 -99
- data/spec/builtins/and_spec.rb +0 -22
- data/spec/builtins/array_spec.rb +0 -16
- data/spec/builtins/branch_or_spec.rb +0 -27
- data/spec/builtins/cut_spec.rb +0 -44
- data/spec/builtins/fail_spec.rb +0 -5
- data/spec/builtins/false_spec.rb +0 -5
- data/spec/builtins/in_spec.rb +0 -38
- data/spec/builtins/is_false_spec.rb +0 -12
- data/spec/builtins/is_spec.rb +0 -26
- data/spec/builtins/matches_spec.rb +0 -23
- data/spec/builtins/or_spec.rb +0 -22
- data/spec/builtins/splits_to.rb +0 -18
- data/spec/builtins/then_spec.rb +0 -27
- data/spec/builtins/true_spec.rb +0 -5
- data/spec/compilation_spec.rb +0 -61
- data/spec/custom_classes_spec.rb +0 -43
- data/spec/dereference.rb +0 -10
- data/spec/queries_spec.rb +0 -150
- data/spec/recursion_spec.rb +0 -18
- data/spec/ruby_code_spec.rb +0 -52
- data/spec/rules_spec.rb +0 -97
- data/spec/theory_spec.rb +0 -29
- data/spec/variable_spec.rb +0 -26
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rubylog::Assertable
|
2
|
+
# Asserts a rule with the receiver as the head and the given argument or
|
3
|
+
# block as the body to the head's predicate.
|
4
|
+
def if body=nil, &block
|
5
|
+
raise Rubylog::SyntaxError, "No body given", caller unless body || block
|
6
|
+
predicate.assert(self, body || block)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Asserts a rule with the receiver as the head and the given argument or
|
10
|
+
# block as the body to the head's predicate. Prepends a :cut! in front of the
|
11
|
+
# body with and .and().
|
12
|
+
#
|
13
|
+
def if! body=nil, &block
|
14
|
+
raise Rubylog::SyntaxError, "No body given", caller unless body || block
|
15
|
+
predicate.assert self, :cut!.and(body || block)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Asserts a rule with the receiver as the head and the given argument or
|
19
|
+
# block as the body to the head's predicate. Adds a .false to the body.
|
20
|
+
def unless body=nil, &block
|
21
|
+
raise Rubylog::SyntaxError, "No body given", caller unless body || block
|
22
|
+
predicate.assert self, Rubylog::DefaultContext.false(body || block)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
rubylog do
|
2
|
+
|
3
|
+
class << primitives_for Numeric
|
4
|
+
# Succeeds if +c+ unifies with the sum of +a+ and +b+ if +a+ and +b+ is given.
|
5
|
+
# Succeeds if +a+ unifies with the difference of +c+ and +b+ if +c+ and +b+ is given.
|
6
|
+
# Succeeds if +b+ unifies with the difference of +c+ and +a+ if +c+ and +a+ is given.
|
7
|
+
#
|
8
|
+
# +a+ and +b+ can be procs.
|
9
|
+
#
|
10
|
+
# Please beware that unification requires equality by type, so 4.sum_of(2, 2.0) will fail.
|
11
|
+
#
|
12
|
+
# It can add any type of object that responds_to + and/or -:
|
13
|
+
# A.sum_of(B,C).predicate.add_functor_to String
|
14
|
+
# check "hello".sum_of("he", "llo")
|
15
|
+
#
|
16
|
+
def sum_of c, a, b
|
17
|
+
a, b, c = [a,b,c].map{|f|f.rubylog_resolve_function.rubylog_dereference}
|
18
|
+
a_var, b_var, c_var = [a,b,c].map{|f|f.is_a? Rubylog::Variable}
|
19
|
+
|
20
|
+
case
|
21
|
+
when !a_var && !b_var
|
22
|
+
c.rubylog_unify(a+b) { yield }
|
23
|
+
when !c_var && !b_var
|
24
|
+
a.rubylog_unify(c-b) { yield }
|
25
|
+
when !c_var && !a_var
|
26
|
+
b.rubylog_unify(c-a) { yield }
|
27
|
+
else
|
28
|
+
raise Rubylog::InstantiationError.new :sum_of, [c, a, b]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
# Succeeds if +c+ unifies with the product of +a+ and +b+ if +a+ and +b+ is given.
|
34
|
+
# Succeeds if +a+ unifies with the difference of +c+ and +b+ if +c+ and +b+ is given.
|
35
|
+
# Succeeds if +b+ unifies with the difference of +c+ and +a+ if +c+ and +a+ is given.
|
36
|
+
#
|
37
|
+
# +a+ and +b+ can be procs.
|
38
|
+
#
|
39
|
+
# Please beware that unification requires equality by type, so 4.sum_of(2, 2.0) will fail.
|
40
|
+
#
|
41
|
+
# It can add any type of object that responds_to + and/or -:
|
42
|
+
# A.sum_of(B,C).predicate.add_functor_to String
|
43
|
+
# check "hello".sum_of("he", "llo")
|
44
|
+
#
|
45
|
+
def product_of c, a, b
|
46
|
+
a, b, c = [a,b,c].map{|f|f.rubylog_resolve_function.rubylog_dereference}
|
47
|
+
a_var, b_var, c_var = [a,b,c].map{|f|f.is_a? Rubylog::Variable}
|
48
|
+
|
49
|
+
case
|
50
|
+
when !a_var && !b_var
|
51
|
+
c.rubylog_unify(a*b) { yield }
|
52
|
+
when !c_var && !b_var
|
53
|
+
a.rubylog_unify(c/b) { yield } if ((c/b)*b).eql? c
|
54
|
+
when !c_var && !a_var
|
55
|
+
b.rubylog_unify(c/a) { yield } if (a*(c/a)).eql? c
|
56
|
+
else
|
57
|
+
raise Rubylog::InstantiationError.new :product_of, [c, a, b]
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
rubylog do
|
2
|
+
predicate_for ::Rubylog::Assertable, ".assumed", ".rejected", ".revoked", ".assumed_if()", ".assumed_unless()", ".rejected_if()", ".rejected_unless()"
|
3
|
+
|
4
|
+
# Asserts a rule with head H and body B in the predicate of H. It retracts it
|
5
|
+
# at backtracking.
|
6
|
+
H.assumed_if(B).if proc {
|
7
|
+
raise Rubylog::InstantiationError.new :assumed_if, [H, B] if !H or !B
|
8
|
+
|
9
|
+
# assert
|
10
|
+
H.predicate.unshift Rubylog::Rule.new(H, B)
|
11
|
+
|
12
|
+
true
|
13
|
+
}.ensure {
|
14
|
+
# retract
|
15
|
+
H.predicate.shift
|
16
|
+
}
|
17
|
+
|
18
|
+
# Asserts a fact A to the predicate of A.
|
19
|
+
# The clause is retracted at backtracking.
|
20
|
+
A.assumed.if A.assumed_if :true
|
21
|
+
|
22
|
+
# Asserts a rule H.if(B.false) in the predicate of H.
|
23
|
+
# The clause is retracted at backtracking.
|
24
|
+
H.assumed_unless(B).if H.assumed_if(B.false)
|
25
|
+
|
26
|
+
# Asserts a rule A.if(:cut!.and(:fail)) in the predicate of A.
|
27
|
+
# The clause is retracted at backtracking.
|
28
|
+
A.rejected.if A.assumed_if :cut!.and :fail
|
29
|
+
|
30
|
+
# Asserts a rule H.if(B.and :cut!.and(:fail)) in the predicate of H.
|
31
|
+
# The clause is retracted at backtracking.
|
32
|
+
H.rejected_if(B).if H.assumed_if(B.and :cut!.and :fail)
|
33
|
+
|
34
|
+
# Asserts a rule H.if(B.false.and :cut!.and(:fail)) in the predicate of H.
|
35
|
+
# The clause is retracted at backtracking.
|
36
|
+
H.rejected_unless(B).if H.assumed_if(B.false.and :cut!.and :fail)
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
class << primitives_for ::Rubylog::Assertable
|
41
|
+
# Retracts a rule from the predicate of +h+. At backtracking, the rule is
|
42
|
+
# re-asserted. It consequently succeeds with each rule in the predicate
|
43
|
+
# retracted.
|
44
|
+
#
|
45
|
+
def revoked h
|
46
|
+
h = h.rubylog_dereference
|
47
|
+
raise Rubylog::InstantiationError.new :revoked, [h] if h.is_a? Rubylog::Variable
|
48
|
+
|
49
|
+
predicate = h.predicate
|
50
|
+
|
51
|
+
(0...predicate.size).each do |i|
|
52
|
+
# retract the clause
|
53
|
+
r = predicate.delete_at(i)
|
54
|
+
begin
|
55
|
+
rule = r.rubylog_match_variables
|
56
|
+
rule.head.args.rubylog_unify h.args do
|
57
|
+
rule.body.prove do
|
58
|
+
yield
|
59
|
+
end
|
60
|
+
end
|
61
|
+
ensure
|
62
|
+
# re-assert the clause
|
63
|
+
predicate.insert(i, r)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
end
|
71
|
+
|
@@ -1,15 +1,37 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
functor :filename_in, :dirname_in, :file_in, :dir_in
|
1
|
+
rubylog do
|
2
|
+
predicate_for String, ".filename_in()", ".dirname_in()", ".file_in()", ".dir_in()"
|
4
3
|
|
4
|
+
# If D is not a variable, succeeds if D is a name of an existing directory and
|
5
|
+
# X unifies with a file in directory D. X necessarily starts with # "#{D}/".
|
6
|
+
# Either X or D must be bound. X can contain variables, D cannot.
|
7
|
+
# If D is a variable, it is unified with the dirname of X.
|
8
|
+
#
|
9
|
+
X.file_in(D).if proc{raise Rubylog::InstantiationError.new(:file_in, [X,D]) if D.is_a?(Rubylog::Variable) && X.is_a?(Rubylog::Variable)}
|
10
|
+
X.file_in(D).if proc{! D.is_a?(Rubylog::Variable)}.and X.in {
|
11
|
+
d = D.rubylog_resolve_function
|
12
|
+
Dir["#{d}/*", "#{d}/.*"].sort.select{|x|
|
13
|
+
# exclude . and ..
|
14
|
+
File.basename(x) !~ /\A\.\.?\z/
|
15
|
+
}
|
16
|
+
}
|
17
|
+
X.file_in(D).if proc{! X.is_a? Rubylog::Variable and File.exist?(X)}.and D.is { File.dirname(X) }
|
18
|
+
|
19
|
+
# If D is not a variable, succeeds if X unifies with a directory in directory D. X
|
20
|
+
# necessarily starts with "#{D}/". X can contain variables, D cannot.
|
21
|
+
# If D is a variable, it is unified with the dirname of X.
|
22
|
+
#
|
23
|
+
X.dir_in(D). if X.file_in(D).and { File.directory? X }
|
24
|
+
|
25
|
+
# If D is not a variable, succeeds if X unifies with a name of a file in directory D.
|
26
|
+
# X can contain variables, D cannot. If D is a variable, it is unified with the dirname of X.
|
27
|
+
#
|
5
28
|
X.filename_in(D).if Y.file_in(D).and X.is { File.basename Y }
|
29
|
+
|
30
|
+
# If D is not a variable, succeeds if X unifies with a name of a directory in directory D.
|
31
|
+
# X can contain variables, D cannot. If D is a variable, it is unified with the dirname of X.
|
32
|
+
#
|
6
33
|
X.dirname_in(D).if Y.dir_in(D).and X.is { File.basename Y }
|
7
|
-
X.file_in(D).if Y.in { d = D.rubylog_resolve_function; Dir["#{d}/*", "#{d}/.*"].sort }.and { not ['.','..'].include? File.basename(Y) and not File.directory? Y }.and X.is {File.expand_path Y}
|
8
|
-
X.dir_in(D). if Y.in { d = D.rubylog_resolve_function; Dir["#{d}/*", "#{d}/.*"].sort }.and { not ['.','..'].include? File.basename(Y) and File.directory? Y }.and X.is {File.expand_path Y}
|
9
34
|
|
10
35
|
end
|
11
36
|
|
12
37
|
|
13
|
-
Rubylog::DefaultBuiltins.amend do
|
14
|
-
include Rubylog::FileSystemBuiltins
|
15
|
-
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
rubylog do
|
2
2
|
class << primitives
|
3
3
|
# true
|
4
4
|
def true
|
@@ -15,12 +15,11 @@ Rubylog.theory "Rubylog::NullaryLogicBuiltins", nil do
|
|
15
15
|
throw :cut
|
16
16
|
end
|
17
17
|
end
|
18
|
-
end
|
19
18
|
|
20
|
-
Rubylog.theory "Rubylog::LogicBuiltinsForCallable", nil do
|
21
|
-
subject ::Rubylog::Callable, ::Rubylog::Structure, Symbol, Proc
|
22
19
|
|
23
|
-
|
20
|
+
primitives_for_clause = primitives_for [::Rubylog::Clause, ::Rubylog::Structure]
|
21
|
+
|
22
|
+
class << primitives_for_clause
|
24
23
|
# Succeeds if both +a+ and +b+ succeeds.
|
25
24
|
def and a, b
|
26
25
|
a.prove { b.prove { yield } }
|
@@ -34,14 +33,18 @@ Rubylog.theory "Rubylog::LogicBuiltinsForCallable", nil do
|
|
34
33
|
|
35
34
|
# Succeeds if +a+ does not succeed.
|
36
35
|
def false a
|
37
|
-
|
36
|
+
# catch cuts
|
37
|
+
catch :cut do
|
38
|
+
a.prove { return }
|
39
|
+
end
|
38
40
|
yield
|
39
41
|
end
|
40
42
|
|
41
43
|
# ruby iterator predicate allegories
|
42
44
|
|
43
|
-
#
|
44
|
-
#
|
45
|
+
# Succeeds if for each successful execution of +a+, there exists a solution of +b+.
|
46
|
+
#
|
47
|
+
# Equivalent with <tt>a.and(b.false).false</tt>
|
45
48
|
def all a,b
|
46
49
|
a.prove {
|
47
50
|
stands = false;
|
@@ -51,17 +54,26 @@ Rubylog.theory "Rubylog::LogicBuiltinsForCallable", nil do
|
|
51
54
|
yield
|
52
55
|
end
|
53
56
|
|
54
|
-
#
|
57
|
+
# Succeeds if a and b are equivalent statements
|
58
|
+
#
|
59
|
+
# Equivalent with <tt>a.all(b).and b.all(a)</tt>
|
55
60
|
def iff a,b
|
56
61
|
all(a,b) { all(b,a) { yield } }
|
57
62
|
end
|
58
63
|
|
59
|
-
#
|
60
|
-
|
64
|
+
# Succeeds if for any solution of +a+, +b+ is solveable.
|
65
|
+
#
|
66
|
+
# @param a
|
67
|
+
# @param b defaults to :true
|
68
|
+
def any a,b=:true
|
61
69
|
a.prove { b.prove { yield; return } }
|
62
70
|
end
|
63
71
|
|
64
|
-
|
72
|
+
# Succeeds if there exists one solution of +a+ where +b+ is true.
|
73
|
+
#
|
74
|
+
# @param a
|
75
|
+
# @param b defaults to :true
|
76
|
+
def one a,b=:true
|
65
77
|
stands = false
|
66
78
|
a.prove {
|
67
79
|
b.prove {
|
@@ -72,38 +84,57 @@ Rubylog.theory "Rubylog::LogicBuiltinsForCallable", nil do
|
|
72
84
|
yield if stands
|
73
85
|
end
|
74
86
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
def one a
|
85
|
-
stands = false
|
86
|
-
a.prove {
|
87
|
-
return if stands
|
88
|
-
stands = true
|
87
|
+
# For each successful solutions of +a+, tries to solve +b+. If any of +b+'s
|
88
|
+
# solutions succeeds, it fails, otherwise it succeeds
|
89
|
+
#
|
90
|
+
# Equivalent to <tt>a.all(b.false)</tt>
|
91
|
+
# @param a
|
92
|
+
# @param b defaults to :true
|
93
|
+
def none a,b=:true
|
94
|
+
a.prove {
|
95
|
+
b.prove { return }
|
89
96
|
}
|
90
|
-
yield
|
97
|
+
yield
|
91
98
|
end
|
92
|
-
|
93
|
-
alias none false
|
94
99
|
|
95
100
|
end
|
96
101
|
|
97
|
-
|
98
|
-
|
99
|
-
|
102
|
+
# We also implement some of these methods in a prefix style
|
103
|
+
%w(false all iff any one none).each do |fct|
|
104
|
+
# we discard the first argument, which is the context,
|
105
|
+
# because they are the same in any context
|
106
|
+
primitives_for_context.define_singleton_method fct do |_,*args,&block|
|
107
|
+
primitives_for_clause.send(fct, *args, &block)
|
108
|
+
end
|
109
|
+
end
|
100
110
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
111
|
+
class << primitives_for_context
|
112
|
+
# finds every solution of a, and for each solution dereferences all
|
113
|
+
# variables in b if possible and collects the results. Then joins all b's
|
114
|
+
# with .and() and solves the resulted expression.
|
115
|
+
def every _, a, b
|
116
|
+
c = []
|
117
|
+
a.prove do
|
118
|
+
if b.is_a? Proc
|
119
|
+
# save copies of actual variables
|
120
|
+
vars = a.rubylog_variables.map do |v|
|
121
|
+
new_v = Rubylog::Variable.new(v.name)
|
122
|
+
new_v.send :bind_to!, v.value if v.bound?
|
123
|
+
end
|
124
|
+
|
125
|
+
# store them in a closure
|
126
|
+
b_resolved = proc do
|
127
|
+
b.call_with_rubylog_variables vars
|
128
|
+
end
|
129
|
+
else
|
130
|
+
# dereference actual variables
|
131
|
+
b_resolved = b.rubylog_deep_dereference
|
132
|
+
end
|
133
|
+
c << b_resolved
|
134
|
+
end
|
135
|
+
c.inject(:true){|a,b|a.and b}.solve { yield }
|
136
|
+
end
|
137
|
+
end
|
105
138
|
|
106
|
-
Rubylog::DefaultBuiltins.amend do
|
107
|
-
include Rubylog::LogicBuiltins
|
108
139
|
end
|
109
140
|
|
@@ -1,54 +1,47 @@
|
|
1
|
-
|
2
|
-
subject Rubylog::Structure
|
1
|
+
rubylog do
|
3
2
|
|
4
|
-
class <<
|
3
|
+
class << primitives_for Rubylog::Structure
|
5
4
|
|
6
|
-
# Succeeds if +c+ is a structure, with functor +fct+ and arguments +args+
|
7
|
-
def structure c, fct, args
|
5
|
+
# Succeeds if +c+ is a structure, with predicate +predicate+, functor +fct+ and arguments +args+
|
6
|
+
def structure c, predicate, fct, args
|
8
7
|
c = c.rubylog_dereference
|
9
8
|
if c.is_a? Rubylog::Variable
|
9
|
+
predicate = predicate.rubylog_dereference
|
10
10
|
fct = fct.rubylog_dereference
|
11
11
|
args = args.rubylog_dereference
|
12
|
+
|
12
13
|
# We enable variable functors
|
13
14
|
#raise Rubylog::InstantiationError, fct if fct.is_a? Rubylog::Variable
|
14
|
-
|
15
|
-
|
15
|
+
|
16
|
+
raise Rubylog::InstantiationError.new :structure, [c, predicate, fct, args] if args.is_a? Rubylog::Variable
|
17
|
+
|
18
|
+
c.rubylog_unify(Rubylog::Structure.new(predicate, fct, *args)) { yield }
|
16
19
|
elsif c.is_a? Rubylog::Structure
|
17
|
-
c.
|
18
|
-
c.
|
19
|
-
|
20
|
+
c.predicate.rubylog_unify predicate do
|
21
|
+
c.functor.rubylog_unify fct do
|
22
|
+
c.args.rubylog_unify args do
|
23
|
+
yield
|
24
|
+
end
|
20
25
|
end
|
21
26
|
end
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
#_arity = Rubylog::Variable.new(:_arity)
|
29
|
-
#l.rubylog_unify [f, a] do
|
30
|
-
#if f = _functor.value
|
31
|
-
## TODO
|
32
|
-
#else
|
33
|
-
## TODO
|
34
|
-
#end
|
35
|
-
#end
|
36
|
-
#end
|
30
|
+
end
|
31
|
+
|
32
|
+
class << primitives_for [Rubylog::Assertable, ::Rubylog::Structure]
|
37
33
|
|
38
34
|
# Succeeds if +head+ unifies with a fact.
|
39
35
|
def fact head
|
40
36
|
head = head.rubylog_dereference
|
41
|
-
raise Rubylog::InstantiationError, head if head.is_a? Rubylog::Variable
|
37
|
+
raise Rubylog::InstantiationError.new :fact, [head] if head.is_a? Rubylog::Variable
|
42
38
|
return yield if head == :true
|
43
39
|
return unless head.respond_to? :functor
|
44
|
-
predicate
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
rule[0].args.rubylog_unify head.args do
|
50
|
-
yield
|
51
|
-
end
|
40
|
+
head.predicate.each do |rule|
|
41
|
+
if rule.body == :true
|
42
|
+
rule = rule.rubylog_match_variables
|
43
|
+
rule.head.args.rubylog_unify head.args do
|
44
|
+
yield
|
52
45
|
end
|
53
46
|
end
|
54
47
|
end
|
@@ -58,17 +51,14 @@ Rubylog.theory "Rubylog::ReflectionBuiltinsForStructure", nil do
|
|
58
51
|
# this rule's body.
|
59
52
|
def follows_from head, body
|
60
53
|
head = head.rubylog_dereference
|
61
|
-
raise Rubylog::InstantiationError, head if head.is_a? Rubylog::Variable
|
62
|
-
|
63
|
-
predicate
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
rule
|
68
|
-
|
69
|
-
rule[1].rubylog_unify body do
|
70
|
-
yield
|
71
|
-
end
|
54
|
+
raise Rubylog::InstantiationError.new :follows_from, [head, body] if head.is_a? Rubylog::Variable
|
55
|
+
|
56
|
+
head.predicate.each do |rule|
|
57
|
+
unless rule.body==:true # do not succeed for facts
|
58
|
+
rule = rule.rubylog_match_variables
|
59
|
+
rule.head.args.rubylog_unify head.args do
|
60
|
+
rule.body.rubylog_unify body do
|
61
|
+
yield
|
72
62
|
end
|
73
63
|
end
|
74
64
|
end
|
@@ -80,15 +70,10 @@ Rubylog.theory "Rubylog::ReflectionBuiltinsForStructure", nil do
|
|
80
70
|
# Removed because of the "every built-in prediate is pure logical" principle
|
81
71
|
#def variable a, name
|
82
72
|
#vars = name.rubylog_variables
|
83
|
-
#raise Rubylog::InvalidStateError, "variables not
|
73
|
+
#raise Rubylog::InvalidStateError, "variables not matched" if not vars
|
84
74
|
#vars.find
|
85
75
|
#end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
Rubylog.theory "Rubylog::ReflectionBuiltins", nil do
|
89
|
-
include Rubylog::ReflectionBuiltinsForStructure
|
90
|
-
end
|
91
76
|
|
92
|
-
|
93
|
-
|
77
|
+
end
|
78
|
+
|
94
79
|
end
|
@@ -1,14 +1,18 @@
|
|
1
|
-
|
2
|
-
subject ::Rubylog::Term
|
1
|
+
rubylog do
|
3
2
|
|
4
|
-
class <<
|
5
|
-
#
|
3
|
+
class << primitives_for Rubylog::Term
|
4
|
+
# Unifies +a+ with +b+. Both can be a proc, which is then called and the result
|
5
|
+
# is taken.
|
6
6
|
def is a,b
|
7
7
|
a = a.rubylog_resolve_function
|
8
8
|
b = b.rubylog_resolve_function
|
9
9
|
a.rubylog_unify(b) { yield }
|
10
10
|
end
|
11
11
|
|
12
|
+
# Unifies +a+ with +b+. Fails if the unification succeeds, otherwise succeeds.
|
13
|
+
#
|
14
|
+
# Both +a+ and +b+ can be a proc, which is then called and the result
|
15
|
+
# is taken.
|
12
16
|
def is_not a,b
|
13
17
|
a = a.rubylog_resolve_function
|
14
18
|
b = b.rubylog_resolve_function
|
@@ -16,18 +20,15 @@ Rubylog.theory "Rubylog::TermBuiltins", nil do
|
|
16
20
|
yield
|
17
21
|
end
|
18
22
|
|
19
|
-
# member
|
23
|
+
# Unifies +a+ with each member of enumerable +b+
|
24
|
+
#
|
25
|
+
# Both +a+ and +b+ can be a proc, which is then called and the result
|
26
|
+
# is taken.
|
20
27
|
def in a,b
|
21
28
|
a = a.rubylog_resolve_function
|
22
29
|
b = b.rubylog_resolve_function.rubylog_dereference
|
23
|
-
if b.
|
24
|
-
Rubylog::
|
25
|
-
a.rubylog_unify(l[-1]) {
|
26
|
-
b.rubylog_unify(l) {
|
27
|
-
yield
|
28
|
-
}
|
29
|
-
}
|
30
|
-
}
|
30
|
+
if b.is_a? Rubylog::Variable
|
31
|
+
raise Rubylog::InstantiationError.new :in, [a,b]
|
31
32
|
else
|
32
33
|
b.each do |e|
|
33
34
|
a.rubylog_unify(e) { yield }
|
@@ -35,13 +36,10 @@ Rubylog.theory "Rubylog::TermBuiltins", nil do
|
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
39
|
+
# Succeeds if +a+ cannot be unified with any member of enumerable +b+.
|
38
40
|
def not_in a, b
|
39
41
|
self.in(a, b) { return }
|
40
42
|
yield
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
44
|
-
|
45
|
-
Rubylog::DefaultBuiltins.amend do
|
46
|
-
include Rubylog::TermBuiltins
|
47
|
-
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
require 'rubylog/builtins/logic'
|
3
|
+
require 'rubylog/builtins/term'
|
4
|
+
require 'rubylog/builtins/file_system'
|
5
|
+
require 'rubylog/builtins/ensure'
|
6
|
+
require 'rubylog/builtins/assumption'
|
7
|
+
require 'rubylog/builtins/reflection'
|
8
|
+
require 'rubylog/builtins/arithmetics'
|
9
|
+
|
10
|
+
|
11
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rubylog::Clause
|
2
|
+
# Clients should implement this method.
|
3
|
+
# Yields for each possible solution of the predicate
|
4
|
+
def prove
|
5
|
+
raise "#{self.class} should implement #prove"
|
6
|
+
end
|
7
|
+
|
8
|
+
def true?
|
9
|
+
solve { return true }
|
10
|
+
false
|
11
|
+
end
|
12
|
+
|
13
|
+
def solve &block
|
14
|
+
goal = rubylog_match_variables
|
15
|
+
catch :cut do
|
16
|
+
goal.prove { block.call_with_rubylog_variables(goal.rubylog_variables) if block }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
module Rubylog::
|
2
|
-
def
|
1
|
+
module Rubylog::CompoundTerm
|
2
|
+
def rubylog_match_variables
|
3
3
|
vars = []; vars_by_name = {}
|
4
4
|
rubylog_clone do |subterm|
|
5
5
|
case subterm
|
@@ -21,7 +21,7 @@ module Rubylog::CompositeTerm
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
when Rubylog::
|
24
|
+
when Rubylog::CompoundTerm
|
25
25
|
subterm.instance_variable_set :"@rubylog_variables", vars
|
26
26
|
subterm
|
27
27
|
else
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
require 'rubylog/dsl/variables'
|
3
|
+
require 'rubylog/context_modules/checks'
|
4
|
+
require 'rubylog/context_modules/demonstration'
|
5
|
+
require 'rubylog/context_modules/predicates'
|
6
|
+
require 'rubylog/context_modules/primitives'
|
7
|
+
require 'rubylog/context_modules/thats'
|
8
|
+
|
9
|
+
# The context class represents a collection of rules.
|
10
|
+
|
11
|
+
module Rubylog::Context
|
12
|
+
|
13
|
+
|
14
|
+
include Rubylog::ContextModules::Checks
|
15
|
+
include Rubylog::ContextModules::Demonstration
|
16
|
+
include Rubylog::ContextModules::Predicates
|
17
|
+
include Rubylog::ContextModules::Primitives
|
18
|
+
include Rubylog::ContextModules::Thats
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|