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
@@ -1,5 +1,6 @@
1
1
  module Kernel
2
- def theory *args, &block
3
- Rubylog.theory *args, &block
2
+ # Calls the given block within the default Rubylog context (::Rubylog)
3
+ def rubylog &block
4
+ Rubylog::DefaultContext.instance_exec &block
4
5
  end
5
6
  end
@@ -1,3 +1,2 @@
1
1
  class Method
2
- include Rubylog::Predicate
3
2
  end
@@ -2,7 +2,8 @@ class Object
2
2
  include Rubylog::Term
3
3
 
4
4
  def rubylog_matches_as_guard? other
5
- Rubylog.current_theory.print_trace 0, "#{inspect}===#{other.inspect}"
6
5
  self === other
7
6
  end
7
+
8
+ rubylog_traceable :rubylog_matches_as_guard?
8
9
  end
@@ -1,14 +1,14 @@
1
1
  class Proc
2
2
 
3
- # Callable methods
4
- include Rubylog::Callable
3
+ # Clause methods
4
+ include Rubylog::Clause
5
5
 
6
6
  def prove
7
7
  yield if call_with_rubylog_variables
8
8
  end
9
9
 
10
- # CompositeTerm methods
11
- include Rubylog::CompositeTerm
10
+ # CompoundTerm methods
11
+ include Rubylog::CompoundTerm
12
12
  def rubylog_clone
13
13
  yield dup
14
14
  end
@@ -20,18 +20,15 @@ class Proc
20
20
  call_with_rubylog_variables
21
21
  end
22
22
 
23
+ # Calls the proc with the given rubylog variables or with the currently
24
+ # available variables.
23
25
  def call_with_rubylog_variables vars = nil
24
26
  vars ||= @rubylog_variables
25
- raise Rubylog::InvalidStateError, "variables not available" if not vars
27
+ raise Rubylog::InvalidStateError, "Variables not matched" if not vars
26
28
 
27
- Rubylog::Theory.with_vars vars do
29
+ # Call the block with the variables substituted
30
+ Rubylog::DSL::Variables.with_vars vars do
28
31
  return call
29
32
  end
30
- # to pass arguments:
31
- #if arity == -1
32
- # call *@rubylog_variables.map{|v|v.value}
33
- #else
34
- # call *@rubylog_variables[0...arity].map{|v|v.value}
35
- #end
36
33
  end
37
34
  end
@@ -6,11 +6,9 @@ class String
6
6
  RubylogStringVariableGuards = [[]]
7
7
 
8
8
  def self.rubylog_unify_strings a, a_segments, a_vars, b
9
- #p a, a_segments, a_vars, b
10
9
  if a_segments.count == 1
11
10
  segment = a_segments[0]
12
11
  if b.end_with?(segment)
13
- #p b[0...b.length-segment.length]
14
12
  a_vars[0].rubylog_unify b[0...b.length-segment.length] do
15
13
  yield
16
14
  end
@@ -34,7 +32,7 @@ class String
34
32
  other_has_vars = other =~ RUBYLOG_VAR_REGEXP
35
33
 
36
34
  return super{yield} unless self_has_vars or other_has_vars
37
- raise Rubylog::InstantiationError, "Cannot unify two strings with variables inside" if self_has_vars and other_has_vars
35
+ raise ArgumentError, "Cannot unify two strings with variables inside" if self_has_vars and other_has_vars
38
36
 
39
37
  a, b = self_has_vars ? [self, other] : [other, self]
40
38
  a_segments, a_vars = a.rubylog_segments
@@ -48,8 +46,8 @@ class String
48
46
 
49
47
  end
50
48
 
51
- # CompositeTerm methods
52
- include Rubylog::CompositeTerm
49
+ # CompoundTerm methods
50
+ include Rubylog::CompoundTerm
53
51
  def rubylog_clone &block
54
52
  scan RUBYLOG_VAR_REGEXP do
55
53
  guards = RubylogStringVariableGuards[$2.to_i]
@@ -60,45 +58,39 @@ class String
60
58
 
61
59
  def rubylog_deep_dereference
62
60
  gsub RUBYLOG_VAR_REGEXP do
63
- rubylog_get_string_variable($1).rubylog_deep_dereference.to_s
61
+ rubylog_get_string_variable($1,$2).rubylog_deep_dereference.to_s
64
62
  end
65
63
  end
66
64
 
67
- # returns a list of substrings which are before, between and after the rubylog
68
- # string variables
65
+ # returns a list of substrings which are before, between and after the
66
+ # rubylog
67
+ # string variables, and the list of variabes in between
69
68
  def rubylog_segments
70
69
  segments = [[0]]
71
70
  vars = []
72
71
 
73
72
  scan RUBYLOG_VAR_REGEXP do
74
73
  match = Regexp.last_match
75
- #p match
76
- #p match.begin(0)
77
- #p match.end(0)
78
- #p match[0]
79
- #p match[1]
80
74
  segments.last << match.begin(0)
81
75
  segments << [match.end(0)]
82
- vars << rubylog_get_string_variable(match[1])
76
+ vars << rubylog_get_string_variable(match[1], match[2])
83
77
  end
84
78
 
85
79
 
86
80
  segments.last << length
87
- #p segments, vars
88
81
  segments = segments.map{|s|self[s[0]...s[1]]}
89
- #p [self, segments, vars]
90
82
  return segments, vars
91
83
  end
92
84
 
93
85
  protected
94
86
 
95
- def rubylog_get_string_variable s
96
- s = s.to_sym
97
- if @rubylog_variables
98
- @rubylog_variables.find{|v|v.name == s}
99
- else
100
- raise Rubylog::InvalidStateError, "Rubylog variables not available"
101
- end
87
+ #
88
+ def rubylog_get_string_variable name, guards_index
89
+ name = name.to_sym
90
+ raise Rubylog::InvalidStateError, "Variables not matched" unless @rubylog_variables
91
+
92
+ @rubylog_variables.find{|v|v.name == name} ||
93
+ Rubylog::Variable.new[*RubylogStringVariableGuards[guards_index.to_i]]
102
94
  end
103
95
 
104
96
  end
@@ -1,16 +1,7 @@
1
1
  class Symbol
2
2
 
3
- # a proxy for Structure
4
- def functor
5
- self
6
- end
7
-
8
- def arity
9
- 0
10
- end
11
-
12
- def indicator
13
- [self, 0]
3
+ def predicate
4
+ Rubylog::NullaryPredicates[self] or raise Rubylog::ExistenceError.new(self)
14
5
  end
15
6
 
16
7
  def args
@@ -23,22 +14,14 @@ class Symbol
23
14
  # Term methods
24
15
  include Rubylog::Term
25
16
 
26
- # Callable methods
27
- include Rubylog::Callable
17
+ # Clause methods
18
+ include Rubylog::Clause
28
19
 
29
20
  def prove
30
- begin
31
- Rubylog.current_theory.print_trace 1, self, rubylog_variables_hash
32
-
33
- predicate = Rubylog.current_theory[[self,0]]
34
- raise Rubylog::ExistenceError, indicator if not predicate
35
-
36
- predicate.call(*args) { yield }
37
-
38
- ensure
39
- Rubylog.current_theory.print_trace -1
40
- end
21
+ predicate.call { yield }
41
22
  end
42
23
 
24
+ rubylog_traceable :prove
25
+
43
26
 
44
27
  end
@@ -0,0 +1,3 @@
1
+ module Rubylog
2
+ NullaryPredicates = {}
3
+ end
@@ -0,0 +1,53 @@
1
+ module Rubylog
2
+ class Predicate
3
+
4
+ attr_reader :functor, :arity
5
+ def initialize functor, arity
6
+ @functor = functor
7
+ @arity = arity
8
+ end
9
+
10
+ # Yields for each solution of the predicate
11
+ def call *args
12
+ raise "abstract method called on #{self.inspect}"
13
+ end
14
+
15
+ def add_functor_to subjects
16
+ if arity == 0
17
+ # We treat nullary predicates differently. Do not even create functors.
18
+ Rubylog::NullaryPredicates[functor] = self
19
+ return
20
+ end
21
+
22
+ predicate = self
23
+
24
+ [subjects].flatten.each do |subject|
25
+ raise ArgumentError, "#{subject.inspect} is not a class or module" unless subject.is_a? Module
26
+ subject.class_eval do
27
+ f = predicate.functor
28
+ define_method f do |*args, &block|
29
+ args << block if block
30
+ Rubylog::Structure.new predicate, f, self, *args
31
+ end
32
+
33
+ f_bang = :"#{f}!"
34
+ define_method f_bang do |*args, &block|
35
+ args << block if block
36
+ predicate.assert Rubylog::Structure.new(predicate, f, self, *args), :true
37
+ self
38
+ end
39
+
40
+ f_qmark = :"#{f}?"
41
+ define_method f_qmark do |*args, &block|
42
+ args << block if block
43
+ Rubylog::Structure.new(predicate, f, self, *args).true?
44
+ end
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+
51
+
52
+ end
53
+ end
@@ -0,0 +1,15 @@
1
+ module Rubylog
2
+ class Primitive < Predicate
3
+
4
+ def initialize functor, callable
5
+ super functor, callable.arity
6
+ @callable = callable
7
+ end
8
+
9
+ # calls the callable with the argumens
10
+ def call *args
11
+ @callable.call(*args) { yield }
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ module Rubylog
2
+ class Procedure < Predicate
3
+ include Enumerable
4
+
5
+ def initialize functor, arity, rules=Array.new
6
+ super functor, arity
7
+ @rules = rules
8
+ end
9
+
10
+ def method_missing name, *args, &block
11
+ @rules.send name, *args, &block
12
+ end
13
+
14
+ # accepts the *args of the called structure
15
+ def call *args
16
+ # catch cuts
17
+ catch :cut do
18
+
19
+ # for each rule
20
+ each do |rule|
21
+ # compile
22
+ rule = rule.rubylog_match_variables
23
+
24
+ # unify the head with the arguments
25
+ rule.head.args.rubylog_unify(args) do
26
+ # call the body
27
+ rule.body.prove do
28
+ yield
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ rubylog_traceable :call
35
+
36
+ # Asserts a rule with a given head and body.
37
+ def assert head, body=:true
38
+ push Rubylog::Rule.new(head, body)
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ module Rubylog
2
+
3
+ # This is an internally used class that represents a rule of a predicate.
4
+ #
5
+ class Rule
6
+ attr_reader :head, :body
7
+
8
+ def initialize head, body
9
+ @head = head
10
+ @body = body
11
+ end
12
+
13
+ # CompoundTerm methods
14
+ include Rubylog::CompoundTerm
15
+ def rubylog_clone &block
16
+ block.call Rule.new @head.rubylog_clone(&block), @body.rubylog_clone(&block)
17
+ end
18
+ def rubylog_deep_dereference
19
+ # this is not necessary
20
+ #Rule.new @head.rubylog_deep_dereference, @body.rubylog_deep_dereference
21
+ raise "Not implemented."
22
+ end
23
+ end
24
+ end
@@ -3,13 +3,19 @@ module Rubylog
3
3
 
4
4
  # data structure
5
5
  attr_reader :functor, :args
6
- def initialize functor, *args
6
+
7
+ def initialize predicate, functor, *args
7
8
  #raise Rubylog::TypeError, "functor cannot be #{functor}" unless functor.is_a? Symbol
9
+ @predicate = predicate
8
10
  @functor = functor
9
11
  @args = args.freeze
10
12
  @arity = args.count
11
13
  end
12
14
 
15
+ def predicate
16
+ @predicate
17
+ end
18
+
13
19
  def [] i
14
20
  @args[i]
15
21
  end
@@ -45,21 +51,15 @@ module Rubylog
45
51
  # Assertable methods
46
52
  include Rubylog::Assertable
47
53
 
48
- # Callable methods
49
- include Rubylog::Callable
54
+ # Clause methods
55
+ include Rubylog::Clause
50
56
 
51
57
  def prove
52
- begin
53
- Rubylog.current_theory.print_trace 1, self, rubylog_variables_hash
54
- predicate = Rubylog.current_theory[indicator]
55
- raise Rubylog::ExistenceError, indicator.inspect if not predicate
56
- count = 0
57
- predicate.call(*@args) { yield; count+=1 }
58
- count
59
- ensure
60
- Rubylog.current_theory.print_trace -1
61
- end
58
+ count = 0
59
+ predicate.call(*@args) { yield; count+=1 }
60
+ count
62
61
  end
62
+ rubylog_traceable :prove
63
63
 
64
64
 
65
65
  # enumerable methods
@@ -77,38 +77,19 @@ module Rubylog
77
77
 
78
78
  attr_reader :rubylog_variables
79
79
 
80
- # CompositeTerm methods
81
- include Rubylog::CompositeTerm
80
+ # CompoundTerm methods
81
+ include Rubylog::CompoundTerm
82
+
82
83
  def rubylog_clone &block
83
- block.call Structure.new @functor,
84
+ block.call Structure.new @predicate, @functor.rubylog_clone(&block),
84
85
  *@args.map{|a| a.rubylog_clone &block}
85
86
  end
87
+
86
88
  def rubylog_deep_dereference
87
- Structure.new @functor.rubylog_deep_dereference,
89
+ Structure.new @predicate, @functor.rubylog_deep_dereference,
88
90
  *@args.rubylog_deep_dereference
89
91
  end
90
92
 
91
-
92
- # convenience methods
93
- #def each_solution
94
- #goal = rubylog_compile_variables
95
- #goal.variable_hashes_without_compile.each do |hash|
96
- #yield goal.rubylog_clone {|i| hash[i] || i }
97
- #end
98
- #end
99
-
100
- def variable_hashes
101
- rubylog_compile_variables.variable_hashes_without_compile
102
- end
103
-
104
- protected
105
-
106
- def variable_hashes_without_compile
107
- variables = rubylog_variables
108
- map do |*values|
109
- Hash[variables.zip values]
110
- end
111
- end
112
93
  end
113
94
  end
114
95
 
@@ -11,16 +11,11 @@ module Rubylog::Term
11
11
  self
12
12
  end
13
13
 
14
- def rubylog_variables_hash
15
- vars = rubylog_variables
16
- Hash[vars.zip(vars.map{|v|v.value})]
17
- end
18
-
19
14
  def rubylog_unify other
20
15
  if other.kind_of? Rubylog::Variable
21
16
  other.rubylog_unify(self) do yield end
22
17
  else
23
- yield if self == other
18
+ yield if self.eql? other
24
19
  end
25
20
  end
26
21
 
@@ -32,7 +27,7 @@ module Rubylog::Term
32
27
  self
33
28
  end
34
29
 
35
- def rubylog_compile_variables
30
+ def rubylog_match_variables
36
31
  self
37
32
  end
38
33
  end
@@ -0,0 +1,75 @@
1
+ class Class
2
+ def rubylog_traceable name
3
+ Rubylog.traceable instance_method(name)
4
+ end
5
+ end
6
+
7
+ module Rubylog
8
+ module Tracing
9
+ attr_reader :traceable_methods
10
+ attr_accessor :trace_levels
11
+
12
+ # Turns trace on. If value is given and is false, turns trace off. If a
13
+ # block is given, calls the block with trace on.
14
+ #
15
+ def trace value=true
16
+ if not block_given?
17
+ @trace = value
18
+ @trace_levels = 0
19
+ update_trace
20
+ else
21
+ begin
22
+ trace
23
+ return yield
24
+ ensure
25
+ trace false
26
+ end
27
+ end
28
+ end
29
+
30
+ # returns true if tracing is active
31
+ def trace?
32
+ @trace
33
+ end
34
+
35
+
36
+ def traceable method
37
+ @traceable_methods ||= []
38
+ @traceable_methods << method
39
+ end
40
+
41
+ private
42
+
43
+ def update_trace
44
+ if trace?
45
+ traceable_methods.each do |m|
46
+ m.owner.send :define_method, m.name do |*args,&block|
47
+ begin
48
+ print " "*Rubylog.trace_levels
49
+ Rubylog.trace_levels += 1
50
+ print "#{inspect}.#{m.name}(#{args.map{|k|k.inspect}.join(", ")})?"
51
+ gets
52
+
53
+ return m.bind(self).call *args, &block
54
+ ensure
55
+ Rubylog.trace_levels -= 1
56
+ print " "*Rubylog.trace_levels
57
+ print "*"
58
+ puts
59
+ end
60
+ end
61
+ end
62
+ else
63
+ traceable_methods.each do |m|
64
+ m.owner.send :define_method, m.name do |*args, &block|
65
+ m.bind(self).call(*args, &block)
66
+ end
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ extend Tracing
73
+ end
74
+
75
+
@@ -35,8 +35,7 @@ module Rubylog
35
35
 
36
36
 
37
37
  def value
38
- return nil if (val = rubylog_dereference).kind_of? Variable
39
- val
38
+ @value if @bound
40
39
  end
41
40
 
42
41
  def dont_care?
@@ -51,7 +50,13 @@ module Rubylog
51
50
  [self]
52
51
  end
53
52
 
54
- # unify two variables
53
+ # Unifies the receiver with another value.
54
+ #
55
+ # First dereferences both the receiver and the other. If both dereferenced
56
+ # values are variables, unifies them with the other being bound to the
57
+ # receiver. If one of them is a variable, it gets bound to the other value.
58
+ # If none of them is a variable, they are checked for equality with eql?.
59
+ #
55
60
  def rubylog_unify other
56
61
  # check if we are bound
57
62
  if @bound
@@ -68,7 +73,9 @@ module Rubylog
68
73
  if other.is_a? Rubylog::Variable
69
74
  # we union our guards with the other's
70
75
  other.append_guards guards do
71
- bind_to other do
76
+ # we bind the other to self (this order comes from
77
+ # inriasuite_spec#unify)
78
+ other.bind_to self do
72
79
  yield
73
80
  end
74
81
  end
@@ -102,13 +109,21 @@ module Rubylog
102
109
  end
103
110
  end
104
111
 
105
- # Callable methods
106
- include Callable
112
+ # Clause methods
113
+ include Clause
107
114
 
108
115
  def prove
109
- v = value
110
- raise InstantiationError, self if v.nil?
111
- v.prove{yield}
116
+ v = rubylog_dereference
117
+ raise Rubylog::InstantiationError.new(self) if v.is_a? Rubylog::Variable
118
+
119
+ # match variables if not matched
120
+ unless v.rubylog_variables
121
+ v = v.rubylog_match_variables
122
+ end
123
+
124
+ catch :cut do
125
+ v.prove{yield}
126
+ end
112
127
  end
113
128
 
114
129
 
@@ -145,15 +160,19 @@ module Rubylog
145
160
  def bind_to other
146
161
  begin
147
162
  @bound = true; @value = other
148
- Rubylog.current_theory.print_trace 1, "#{inspect}=#{@value.inspect}"
149
163
 
150
164
  yield
151
-
152
165
  ensure
153
166
  @bound = false
154
- Rubylog.current_theory.print_trace -1
155
167
  end
156
168
  end
169
+ rubylog_traceable :bind_to
170
+
171
+ def bind_to! other
172
+ @bound = true; @value = other
173
+ self
174
+ end
175
+ private :bind_to!
157
176
 
158
177
  # yields with self.guards = self.guards + other_guards, then restores guards
159
178
  def append_guards other_guards