rubylog 1.0.0 → 2.0pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. data/Gemfile +3 -12
  2. data/Gemfile.lock +22 -48
  3. data/README.rdoc +38 -38
  4. data/README.rdoc.orig +284 -0
  5. data/RELEASE_NOTES.rdoc +51 -0
  6. data/Rakefile +14 -18
  7. data/TODO.txt +0 -0
  8. data/VERSION +1 -1
  9. data/examples/a_plus_b.rb +6 -0
  10. data/examples/checkmate.rb +88 -0
  11. data/examples/combination.rb +17 -0
  12. data/examples/dcg.rb +3 -2
  13. data/examples/dcg2.rb +2 -2
  14. data/{logic → examples}/directory_structure_logic.rb +3 -5
  15. data/examples/dirlist.rb +4 -0
  16. data/examples/divisors.rb +6 -0
  17. data/examples/enumerators.rb +3 -3
  18. data/examples/factorial.rb +2 -3
  19. data/examples/file_search.rb +14 -0
  20. data/examples/hanoi.rb +4 -5
  21. data/examples/hello.rb +6 -4
  22. data/examples/mice.rb +92 -0
  23. data/examples/mice2.rb +19 -0
  24. data/examples/n_queens.rb +32 -0
  25. data/examples/object_oriented.rb +14 -0
  26. data/examples/palindrome_detection.rb +18 -0
  27. data/examples/parsing.rb +6 -4
  28. data/examples/permutation.rb +12 -0
  29. data/examples/prefix.rb +13 -0
  30. data/examples/primality_by_division.rb +22 -0
  31. data/examples/primitives.rb +10 -8
  32. data/examples/sieve_of_eratosthenes.rb +14 -0
  33. data/examples/string_interpolation.rb +4 -0
  34. data/examples/sudoku.rb +52 -0
  35. data/examples/tracing.rb +19 -0
  36. data/lib/rspec/rubylog.rb +29 -0
  37. data/lib/rubylog/assertable.rb +24 -0
  38. data/lib/rubylog/builtins/arithmetics.rb +63 -0
  39. data/lib/rubylog/builtins/assumption.rb +71 -0
  40. data/lib/rubylog/builtins/ensure.rb +13 -0
  41. data/lib/rubylog/builtins/file_system.rb +30 -8
  42. data/lib/rubylog/builtins/logic.rb +69 -38
  43. data/lib/rubylog/builtins/reflection.rb +35 -50
  44. data/lib/rubylog/builtins/term.rb +15 -17
  45. data/lib/rubylog/builtins.rb +11 -0
  46. data/lib/rubylog/clause.rb +19 -0
  47. data/lib/rubylog/{interfaces/composite_term.rb → compound_term.rb} +3 -3
  48. data/lib/rubylog/context.rb +24 -0
  49. data/lib/rubylog/context_creation.rb +71 -0
  50. data/lib/rubylog/context_modules/checks.rb +35 -0
  51. data/lib/rubylog/context_modules/demonstration.rb +16 -0
  52. data/lib/rubylog/context_modules/predicates.rb +86 -0
  53. data/lib/rubylog/context_modules/primitives.rb +18 -0
  54. data/lib/rubylog/context_modules/thats.rb +13 -0
  55. data/lib/rubylog/default_context.rb +9 -0
  56. data/lib/rubylog/dsl/array_splat.rb +11 -3
  57. data/lib/rubylog/dsl/primitives.rb +24 -12
  58. data/lib/rubylog/dsl/thats.rb +6 -0
  59. data/lib/rubylog/dsl/variables.rb +56 -21
  60. data/lib/rubylog/errors.rb +26 -15
  61. data/lib/rubylog/mixins/array.rb +95 -62
  62. data/lib/rubylog/mixins/kernel.rb +3 -2
  63. data/lib/rubylog/mixins/method.rb +0 -1
  64. data/lib/rubylog/mixins/object.rb +2 -1
  65. data/lib/rubylog/mixins/proc.rb +9 -12
  66. data/lib/rubylog/mixins/string.rb +15 -23
  67. data/lib/rubylog/mixins/symbol.rb +7 -24
  68. data/lib/rubylog/nullary_predicates.rb +3 -0
  69. data/lib/rubylog/predicate.rb +53 -0
  70. data/lib/rubylog/primitive.rb +15 -0
  71. data/lib/rubylog/procedure.rb +42 -0
  72. data/lib/rubylog/rule.rb +24 -0
  73. data/lib/rubylog/structure.rb +19 -38
  74. data/lib/rubylog/{interfaces/term.rb → term.rb} +2 -7
  75. data/lib/rubylog/tracing.rb +75 -0
  76. data/lib/rubylog/variable.rb +31 -12
  77. data/lib/rubylog.rb +36 -32
  78. data/rubylog.gemspec +92 -84
  79. data/spec/inriasuite_spec.rb +906 -9
  80. data/spec/integration/custom_classes_spec.rb +61 -0
  81. data/spec/integration/dsl_spec.rb +38 -0
  82. data/spec/integration/recursion_spec.rb +14 -0
  83. data/spec/integration/theory_as_module_spec.rb +20 -0
  84. data/spec/integration/theory_as_module_with_include_spec.rb +14 -0
  85. data/spec/rspec/rubylog_spec.rb +75 -0
  86. data/spec/rubylog/assertable_spec.rb +111 -0
  87. data/spec/rubylog/builtins/arithmetics_spec.rb +94 -0
  88. data/spec/rubylog/builtins/assumption_spec.rb +70 -0
  89. data/spec/rubylog/builtins/ensure_spec.rb +8 -0
  90. data/spec/rubylog/builtins/file_system_spec.rb +40 -0
  91. data/spec/rubylog/builtins/logic_spec.rb +340 -0
  92. data/spec/rubylog/builtins/reflection_spec.rb +43 -0
  93. data/spec/rubylog/builtins/term_spec.rb +85 -0
  94. data/spec/rubylog/context_modules/demonstration_spec.rb +132 -0
  95. data/spec/rubylog/context_modules/predicates_spec.rb +57 -0
  96. data/spec/rubylog/context_modules/thats_spec.rb +94 -0
  97. data/spec/rubylog/dsl/array_splat_spec.rb +15 -0
  98. data/spec/rubylog/dsl/primitives_spec.rb +43 -0
  99. data/spec/rubylog/errors_spec.rb +18 -0
  100. data/spec/{unification_spec.rb → rubylog/interfaces/term_spec.rb} +8 -9
  101. data/spec/rubylog/mixins/array_spec.rb +80 -0
  102. data/spec/rubylog/mixins/composite_term_spec.rb +66 -0
  103. data/spec/rubylog/mixins/proc_spec.rb +59 -0
  104. data/spec/rubylog/mixins/string_spec.rb +48 -0
  105. data/spec/rubylog/mixins/symbol_spec.rb +9 -0
  106. data/spec/{clause_spec.rb → rubylog/structure_spec.rb} +16 -15
  107. data/spec/rubylog/term_spec.rb +7 -0
  108. data/spec/rubylog/tracing_spec.input +27 -0
  109. data/spec/rubylog/tracing_spec.rb +44 -0
  110. data/spec/rubylog/variable_spec.rb +279 -0
  111. data/spec/spec_helper.rb +1 -0
  112. data/vimrc +11 -0
  113. metadata +103 -123
  114. data/README.hu.rb +0 -58
  115. data/bin/rubylog +0 -18
  116. data/examples/theory.rb +0 -32
  117. data/lib/rubylog/builtins/default.rb +0 -10
  118. data/lib/rubylog/dsl.rb +0 -70
  119. data/lib/rubylog/interfaces/assertable.rb +0 -16
  120. data/lib/rubylog/interfaces/callable.rb +0 -18
  121. data/lib/rubylog/interfaces/predicate.rb +0 -8
  122. data/lib/rubylog/interfaces/procedure.rb +0 -60
  123. data/lib/rubylog/mixins/class.rb +0 -11
  124. data/lib/rubylog/simple_procedure.rb +0 -8
  125. data/lib/rubylog/theory.rb +0 -422
  126. data/logic/builtins/file_system_logic.rb +0 -23
  127. data/logic/builtins/reflection_logic.rb +0 -40
  128. data/logic/dereference_logic.rb +0 -23
  129. data/logic/dsl_logic.rb +0 -29
  130. data/logic/errors_logic.rb +0 -9
  131. data/logic/guard_logic.rb +0 -115
  132. data/logic/list_logic.rb +0 -55
  133. data/logic/map_logic.rb +0 -15
  134. data/logic/multitheory.rb +0 -23
  135. data/logic/recursion_logic.rb +0 -12
  136. data/logic/string_logic.rb +0 -41
  137. data/logic/thats_logic.rb +0 -51
  138. data/logic/variable_logic.rb +0 -24
  139. data/spec/bartak_guide_spec.rb +0 -86
  140. data/spec/builtins/all_spec.rb +0 -99
  141. data/spec/builtins/and_spec.rb +0 -22
  142. data/spec/builtins/array_spec.rb +0 -16
  143. data/spec/builtins/branch_or_spec.rb +0 -27
  144. data/spec/builtins/cut_spec.rb +0 -44
  145. data/spec/builtins/fail_spec.rb +0 -5
  146. data/spec/builtins/false_spec.rb +0 -5
  147. data/spec/builtins/in_spec.rb +0 -38
  148. data/spec/builtins/is_false_spec.rb +0 -12
  149. data/spec/builtins/is_spec.rb +0 -26
  150. data/spec/builtins/matches_spec.rb +0 -23
  151. data/spec/builtins/or_spec.rb +0 -22
  152. data/spec/builtins/splits_to.rb +0 -18
  153. data/spec/builtins/then_spec.rb +0 -27
  154. data/spec/builtins/true_spec.rb +0 -5
  155. data/spec/compilation_spec.rb +0 -61
  156. data/spec/custom_classes_spec.rb +0 -43
  157. data/spec/dereference.rb +0 -10
  158. data/spec/queries_spec.rb +0 -150
  159. data/spec/recursion_spec.rb +0 -18
  160. data/spec/ruby_code_spec.rb +0 -52
  161. data/spec/rules_spec.rb +0 -97
  162. data/spec/theory_spec.rb +0 -29
  163. 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
+
@@ -0,0 +1,13 @@
1
+ rubylog do
2
+
3
+ class << primitives_for ::Rubylog::Clause
4
+ # succeeds if A succeeds. At backtracking, solves B
5
+ def ensure a, b
6
+ begin
7
+ a.prove { yield }
8
+ ensure
9
+ b.prove {}
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,15 +1,37 @@
1
- theory "Rubylog::FileSystemBuiltins", nil do
2
- subject String
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
- Rubylog.theory "Rubylog::NullaryLogicBuiltins", nil do
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
- class << primitives
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
- a.prove { return }
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
- # For each successful execution of +a+, executes +b+. If any of +b+'s
44
- # executions fails, it fails, otherwise it succeeds.
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
- # Equivalent with +a.all(b).and b.all(a)+
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
- def any a,b
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
- def one a,b
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
- def none a,b
76
- a.prove { b.prove { return } }
77
- yield
78
- end
79
-
80
- def any a
81
- a.prove { yield; return }
82
- end
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 if stands
97
+ yield
91
98
  end
92
-
93
- alias none false
94
99
 
95
100
  end
96
101
 
97
- prefix_functor :all, :any, :one, :none, :iff
98
-
99
- end
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
- Rubylog.theory "Rubylog::LogicBuiltins", nil do
102
- include Rubylog::NullaryLogicBuiltins
103
- include Rubylog::LogicBuiltinsForCallable
104
- end
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
- Rubylog.theory "Rubylog::ReflectionBuiltinsForStructure", nil do
2
- subject Rubylog::Structure
1
+ rubylog do
3
2
 
4
- class << primitives
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
- raise Rubylog::InstantiationError, args if args.is_a? Rubylog::Variable
15
- c.rubylog_unify(Rubylog::Structure.new(fct, *args)) { yield }
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.functor.rubylog_unify fct do
18
- c.args.rubylog_unify args do
19
- yield
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
- # I don't remember what this is supposed to be.
26
- #def predicate l
27
- #_functor = Rubylog::Variable.new(:_functor)
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 = Rubylog.current_theory[head.indicator]
45
- if predicate.respond_to? :each # if it is a procedure
46
- predicate.each do |rule|
47
- if rule[1] == :true
48
- rule = rule.rubylog_compile_variables
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
- return unless head.respond_to? :functor
63
- predicate = Rubylog.current_theory[head.indicator]
64
- if predicate.respond_to? :each
65
- predicate.each do |rule|
66
- unless rule[1]==:true # do not succeed for facts
67
- rule = rule.rubylog_compile_variables
68
- rule[0].args.rubylog_unify head.args do
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 available" if not vars
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
- Rubylog::DefaultBuiltins.amend do
93
- include Rubylog::ReflectionBuiltins
77
+ end
78
+
94
79
  end
@@ -1,14 +1,18 @@
1
- Rubylog.theory "Rubylog::TermBuiltins", nil do
2
- subject ::Rubylog::Term
1
+ rubylog do
3
2
 
4
- class << primitives
5
- # = is
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.instance_of? Rubylog::Variable
24
- Rubylog::InternalHelpers.non_empty_list {|l|
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::CompositeTerm
2
- def rubylog_compile_variables
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::CompositeTerm
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
+