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.
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
+