rubylog 1.0.0 → 2.0pre1
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/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
|
+
|