mini_kraken 0.2.03 → 0.3.03

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 (136) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +378 -333
  3. data/CHANGELOG.md +48 -0
  4. data/README.md +29 -21
  5. data/lib/mini_kraken/atomic/all_atomic.rb +5 -0
  6. data/lib/mini_kraken/atomic/atomic_term.rb +96 -0
  7. data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
  8. data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -5
  9. data/lib/mini_kraken/atomic/k_string.rb +17 -0
  10. data/lib/mini_kraken/{core → atomic}/k_symbol.rb +4 -8
  11. data/lib/mini_kraken/composite/all_composite.rb +4 -0
  12. data/lib/mini_kraken/composite/composite_term.rb +27 -0
  13. data/lib/mini_kraken/composite/cons_cell.rb +301 -0
  14. data/lib/mini_kraken/composite/cons_cell_visitor.rb +50 -0
  15. data/lib/mini_kraken/composite/list.rb +32 -0
  16. data/lib/mini_kraken/core/all_core.rb +8 -0
  17. data/lib/mini_kraken/core/any_value.rb +31 -7
  18. data/lib/mini_kraken/core/arity.rb +69 -0
  19. data/lib/mini_kraken/core/association.rb +29 -4
  20. data/lib/mini_kraken/core/association_copy.rb +50 -0
  21. data/lib/mini_kraken/core/base_term.rb +13 -0
  22. data/lib/mini_kraken/core/blackboard.rb +315 -0
  23. data/lib/mini_kraken/core/bookmark.rb +46 -0
  24. data/lib/mini_kraken/core/context.rb +492 -0
  25. data/lib/mini_kraken/core/duck_fiber.rb +21 -19
  26. data/lib/mini_kraken/core/entry.rb +40 -0
  27. data/lib/mini_kraken/core/fail.rb +20 -18
  28. data/lib/mini_kraken/core/fusion.rb +29 -0
  29. data/lib/mini_kraken/core/goal.rb +20 -29
  30. data/lib/mini_kraken/core/log_var.rb +22 -0
  31. data/lib/mini_kraken/core/log_var_ref.rb +108 -0
  32. data/lib/mini_kraken/core/nullary_relation.rb +2 -9
  33. data/lib/mini_kraken/core/parametrized_term.rb +68 -0
  34. data/lib/mini_kraken/core/relation.rb +14 -28
  35. data/lib/mini_kraken/core/scope.rb +67 -0
  36. data/lib/mini_kraken/core/solver_adapter.rb +58 -0
  37. data/lib/mini_kraken/core/specification.rb +48 -0
  38. data/lib/mini_kraken/core/succeed.rb +21 -17
  39. data/lib/mini_kraken/core/symbol_table.rb +137 -0
  40. data/lib/mini_kraken/core/term.rb +15 -4
  41. data/lib/mini_kraken/glue/dsl.rb +44 -88
  42. data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
  43. data/lib/mini_kraken/rela/all_rela.rb +8 -0
  44. data/lib/mini_kraken/rela/binary_relation.rb +30 -0
  45. data/lib/mini_kraken/rela/conde.rb +143 -0
  46. data/lib/mini_kraken/rela/conj2.rb +65 -0
  47. data/lib/mini_kraken/rela/def_relation.rb +93 -0
  48. data/lib/mini_kraken/rela/disj2.rb +70 -0
  49. data/lib/mini_kraken/rela/fresh.rb +98 -0
  50. data/lib/mini_kraken/{core → rela}/goal_relation.rb +7 -9
  51. data/lib/mini_kraken/rela/unify.rb +265 -0
  52. data/lib/mini_kraken/version.rb +1 -1
  53. data/mini_kraken.gemspec +2 -2
  54. data/spec/.rubocop.yml +1 -1
  55. data/spec/atomic/atomic_term_spec.rb +98 -0
  56. data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
  57. data/spec/{core → atomic}/k_symbol_spec.rb +3 -16
  58. data/spec/composite/cons_cell_spec.rb +225 -0
  59. data/spec/{core → composite}/cons_cell_visitor_spec.rb +36 -20
  60. data/spec/composite/list_spec.rb +50 -0
  61. data/spec/core/any_value_spec.rb +52 -0
  62. data/spec/core/arity_spec.rb +92 -0
  63. data/spec/core/association_copy_spec.rb +69 -0
  64. data/spec/core/association_spec.rb +31 -4
  65. data/spec/core/blackboard_spec.rb +287 -0
  66. data/spec/core/bookmark_spec.rb +40 -0
  67. data/spec/core/context_spec.rb +245 -0
  68. data/spec/core/core_spec.rb +40 -0
  69. data/spec/core/duck_fiber_spec.rb +16 -46
  70. data/spec/core/fail_spec.rb +5 -6
  71. data/spec/core/goal_spec.rb +22 -12
  72. data/spec/core/log_var_ref_spec.rb +105 -0
  73. data/spec/core/log_var_spec.rb +64 -0
  74. data/spec/core/nullary_relation_spec.rb +33 -0
  75. data/spec/core/parametrized_tem_spec.rb +39 -0
  76. data/spec/core/relation_spec.rb +33 -0
  77. data/spec/core/scope_spec.rb +73 -0
  78. data/spec/core/solver_adapter_spec.rb +70 -0
  79. data/spec/core/specification_spec.rb +43 -0
  80. data/spec/core/succeed_spec.rb +5 -5
  81. data/spec/core/symbol_table_spec.rb +142 -0
  82. data/spec/glue/dsl_chap1_spec.rb +88 -144
  83. data/spec/glue/dsl_chap2_spec.rb +454 -19
  84. data/spec/glue/run_star_expression_spec.rb +81 -906
  85. data/spec/rela/conde_spec.rb +153 -0
  86. data/spec/rela/conj2_spec.rb +123 -0
  87. data/spec/rela/def_relation_spec.rb +119 -0
  88. data/spec/rela/disj2_spec.rb +117 -0
  89. data/spec/rela/fresh_spec.rb +147 -0
  90. data/spec/rela/unify_spec.rb +369 -0
  91. data/spec/support/factory_atomic.rb +29 -0
  92. data/spec/support/factory_composite.rb +21 -0
  93. data/spec/support/factory_methods.rb +11 -26
  94. metadata +98 -70
  95. data/lib/mini_kraken/core/association_walker.rb +0 -183
  96. data/lib/mini_kraken/core/atomic_term.rb +0 -67
  97. data/lib/mini_kraken/core/base_arg.rb +0 -10
  98. data/lib/mini_kraken/core/binary_relation.rb +0 -63
  99. data/lib/mini_kraken/core/composite_goal.rb +0 -46
  100. data/lib/mini_kraken/core/composite_term.rb +0 -41
  101. data/lib/mini_kraken/core/conde.rb +0 -143
  102. data/lib/mini_kraken/core/conj2.rb +0 -79
  103. data/lib/mini_kraken/core/cons_cell.rb +0 -82
  104. data/lib/mini_kraken/core/cons_cell_visitor.rb +0 -102
  105. data/lib/mini_kraken/core/def_relation.rb +0 -53
  106. data/lib/mini_kraken/core/designation.rb +0 -55
  107. data/lib/mini_kraken/core/disj2.rb +0 -72
  108. data/lib/mini_kraken/core/environment.rb +0 -73
  109. data/lib/mini_kraken/core/equals.rb +0 -193
  110. data/lib/mini_kraken/core/formal_arg.rb +0 -22
  111. data/lib/mini_kraken/core/formal_ref.rb +0 -25
  112. data/lib/mini_kraken/core/freshness.rb +0 -45
  113. data/lib/mini_kraken/core/goal_arg.rb +0 -12
  114. data/lib/mini_kraken/core/goal_template.rb +0 -102
  115. data/lib/mini_kraken/core/k_boolean.rb +0 -35
  116. data/lib/mini_kraken/core/outcome.rb +0 -63
  117. data/lib/mini_kraken/core/variable.rb +0 -41
  118. data/lib/mini_kraken/core/variable_ref.rb +0 -84
  119. data/lib/mini_kraken/core/vocabulary.rb +0 -446
  120. data/lib/mini_kraken/glue/fresh_env.rb +0 -103
  121. data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
  122. data/spec/core/association_walker_spec.rb +0 -192
  123. data/spec/core/conde_spec.rb +0 -147
  124. data/spec/core/conj2_spec.rb +0 -114
  125. data/spec/core/cons_cell_spec.rb +0 -107
  126. data/spec/core/def_relation_spec.rb +0 -97
  127. data/spec/core/disj2_spec.rb +0 -99
  128. data/spec/core/environment_spec.rb +0 -142
  129. data/spec/core/equals_spec.rb +0 -317
  130. data/spec/core/goal_template_spec.rb +0 -74
  131. data/spec/core/outcome_spec.rb +0 -56
  132. data/spec/core/variable_ref_spec.rb +0 -30
  133. data/spec/core/variable_spec.rb +0 -35
  134. data/spec/core/vocabulary_spec.rb +0 -219
  135. data/spec/glue/fresh_env_factory_spec.rb +0 -97
  136. data/spec/glue/fresh_env_spec.rb +0 -62
@@ -1,19 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../spec_helper' # Use the RSpec framework
4
- require_relative '../../lib/mini_kraken/core/goal'
5
- require_relative '../../lib/mini_kraken/core/conde'
6
- require_relative '../../lib/mini_kraken/core/conj2'
7
- require_relative '../../lib/mini_kraken/core/def_relation'
8
- require_relative '../../lib/mini_kraken/core/disj2'
9
- require_relative '../../lib/mini_kraken/core/equals'
10
- require_relative '../../lib/mini_kraken/core/fail'
11
- require_relative '../../lib/mini_kraken/core/formal_arg'
12
- require_relative '../../lib/mini_kraken/core/formal_ref'
13
- require_relative '../../lib/mini_kraken/core/goal_template'
14
- require_relative '../../lib/mini_kraken/core/succeed'
15
-
16
- require_relative '../support/factory_methods'
4
+
5
+ require_relative '../../lib/mini_kraken/core/all_core'
6
+ require_relative '../../lib/mini_kraken/rela/all_rela'
7
+ require_relative '../support/factory_atomic'
8
+ # require_relative '../support/factory_methods'
17
9
 
18
10
  # Load the class under test
19
11
  require_relative '../../lib/mini_kraken/glue/run_star_expression'
@@ -22,15 +14,19 @@ require_relative '../../lib/mini_kraken/glue/run_star_expression'
22
14
  module MiniKraken
23
15
  module Glue
24
16
  describe RunStarExpression do
25
- include FactoryMethods
17
+ include MiniKraken::FactoryAtomic # Use mix-in module
26
18
 
27
19
  let(:pea) { k_symbol(:pea) }
28
20
  let(:pod) { k_symbol(:pod) }
29
- let(:sample_goal) { equals_goal(pea, pod) }
21
+ let(:sample_goal) { unify_goal(pea, pod) }
30
22
  let(:fails) { Core::Goal.new(Core::Fail.instance, []) }
31
23
  let(:succeeds) { Core::Goal.new(Core::Succeed.instance, []) }
32
24
  subject { RunStarExpression.new('q', sample_goal) }
33
25
 
26
+ def unify_goal(arg1, arg2)
27
+ Core::Goal.new(Rela::Unify.instance, [arg1, arg2])
28
+ end
29
+
34
30
  context 'Initialization:' do
35
31
  it 'could be initialized with a name and a goal' do
36
32
  expect { RunStarExpression.new('q', sample_goal) }.not_to raise_error
@@ -40,17 +36,18 @@ module MiniKraken
40
36
  expect { RunStarExpression.new(%w[r x y], sample_goal) }.not_to raise_error
41
37
  end
42
38
 
43
- it 'could be initialized with multiple names and goals' do
44
- expect { RunStarExpression.new(%w[r x y], [succeeds, succeeds]) }.not_to raise_error
45
- end
39
+ # it 'could be initialized with multiple names and goals' do
40
+ # expect { RunStarExpression.new(%w[r x y], [succeeds, succeeds]) }.not_to raise_error
41
+ # end
46
42
 
47
43
  it 'should know its variables' do
48
- expect(subject.env.vars['q']).not_to be_nil
49
- expect(subject.env.vars.values[0].name).to eq('q')
44
+ definitions = subject.ctx.symbol_table.current_scope.defns
45
+ expect(definitions['q']).not_to be_nil
46
+ expect(definitions.values[0].name).to eq('q')
50
47
  end
51
48
 
52
49
  it 'should know its goal' do
53
- expect(subject.env.goal).to eq(sample_goal)
50
+ expect(subject.goal).to eq(sample_goal)
54
51
  end
55
52
  end # context
56
53
 
@@ -70,25 +67,37 @@ module MiniKraken
70
67
  let(:split) { k_symbol(:split) }
71
68
  let(:tea) { k_symbol(:tea) }
72
69
  let(:virgin) { k_symbol(:virgin) }
73
- let(:ref_q) { Core::VariableRef.new('q') }
74
- let(:ref_r) { Core::VariableRef.new('r') }
75
- let(:ref_x) { Core::VariableRef.new('x') }
76
- let(:ref_y) { Core::VariableRef.new('y') }
77
- let(:ref_z) { Core::VariableRef.new('z') }
78
- let(:ref_s) { Core::VariableRef.new('s') }
79
- let(:ref_t) { Core::VariableRef.new('t') }
80
- let(:ref_u) { Core::VariableRef.new('u') }
81
- let(:ref_z) { Core::VariableRef.new('z') }
70
+ let(:ref_q) { Core::LogVarRef.new('q') }
71
+ let(:ref_r) { Core::LogVarRef.new('r') }
72
+ let(:ref_x) { Core::LogVarRef.new('x') }
73
+ let(:ref_y) { Core::LogVarRef.new('y') }
74
+ let(:ref_z) { Core::LogVarRef.new('z') }
75
+ let(:ref_s) { Core::LogVarRef.new('s') }
76
+ let(:ref_t) { Core::LogVarRef.new('t') }
77
+ let(:ref_u) { Core::LogVarRef.new('u') }
78
+ let(:ref_z) { Core::LogVarRef.new('z') }
82
79
  let(:t_ref) { Core::FormalRef.new('t') }
83
- let(:equals_tea) { Core::GoalTemplate.new(Core::Equals.instance, [tea, t_ref]) }
84
- let(:equals_cup) { Core::GoalTemplate.new(Core::Equals.instance, [cup, t_ref]) }
85
- let(:g_template) { Core::GoalTemplate.new(Core::Disj2.instance, [equals_tea, equals_cup]) }
86
- let(:formal_t) { Core::FormalArg.new('t') }
87
80
 
88
- # Reasoned S2, frame 1:82
89
- # (defrel (teacupo t)
90
- # (disj2 (== 'tea t) (== 'cup t)))
91
- let(:teacupo_rel) { Core::DefRelation.new('teacupo', g_template, [formal_t]) }
81
+ # @return [Core::Goal]
82
+ def fresh(names, subgoal)
83
+ # puts "#{__callee__} #{names}"
84
+ if names.kind_of?(Array)
85
+ k_names = names.map { |nm| Atomic::KString.new(nm) }
86
+ else
87
+ k_names = Atomic::KString.new(names)
88
+ end
89
+ Core::Goal.new(Rela::Fresh.instance, [k_names, subgoal])
90
+ end
91
+
92
+ def conj2(term1, term2)
93
+ Core::Goal.new(Rela::Conj2.instance, [term1, term2])
94
+ end
95
+
96
+ def unify(term1, term2)
97
+ Core::Goal.new(Rela::Unify.instance, [term1, term2])
98
+ end
99
+
100
+
92
101
 
93
102
  it 'should return a null list with the fail goal' do
94
103
  # Reasoned S2, frame 1:7
@@ -99,904 +108,70 @@ module MiniKraken
99
108
  expect(instance.run).to be_null
100
109
  end
101
110
 
102
- it 'should return a null list when a goal fails' do
111
+ it 'should return a null list with a failing goal' do
103
112
  # Reasoned S2, frame 1:10
104
- # (run* q (== 'pea 'pod) ;; => ()
105
-
106
- expect(subject.run).to be_null
107
- expect(ref_q.fresh?(subject.env)).to be_truthy
108
- end
109
-
110
- it 'should unify the variable with the equals goal with symbol' do
111
- goal = equals_goal(ref_q, pea)
112
- instance = RunStarExpression.new('q', goal)
113
+ # (run* q (== 'pea 'pod)) ;; => ()
114
+ instance = RunStarExpression.new('q', unify(pea, pod))
113
115
 
114
- # Reasoned S2, frame 1:11
115
- # (run* q (== q 'pea) ;; => (pea)
116
- expect(instance.run.car).to eq(pea)
117
- end
118
-
119
- it 'should unify the righthand variable(s)' do
120
- goal = equals_goal(pea, ref_q)
121
- instance = RunStarExpression.new('q', goal)
122
-
123
- # Reasoned S2, frame 1:12
124
- # (run* q (== 'pea q) ;; => (pea)
125
- expect(instance.run.car).to eq(pea)
116
+ expect(instance.run).to be_null
126
117
  end
127
118
 
128
- it 'should return a null list with the succeed goal' do
129
- instance = RunStarExpression.new('q', succeeds)
130
- expect(instance.env.vars).to be_include('q')
131
-
132
- # (display (run* q succeed)) ;; => (_0)
133
- # Reasoned S2, frame 1:16
134
- result = instance.run
135
-
119
+ it 'should return a _0 with the succeed goal' do
136
120
  # Reasoned S2, frame 1:17
137
- expect(result.car).to eq(any_value(0))
138
- end
121
+ # (run* q #s) ;; => (_0)
122
+ success = Core::Goal.new(Core::Succeed.instance, [])
123
+ instance = RunStarExpression.new('q', success)
139
124
 
140
- it 'should keep variable fresh when no unification occurs (I)' do
141
- goal = equals_goal(pea, pea)
142
- instance = RunStarExpression.new('q', goal)
143
-
144
- # (display (run* q (== 'pea 'pea))) ;; => (_0)
145
- # Reasoned S2, frame 1:19
146
- result = instance.run
147
- expect(result.car).to eq(any_value(0))
148
- end
149
-
150
- it 'should keep variable fresh when no unification occurs (II)' do
151
- ref1_q = Core::VariableRef.new('q')
152
- ref2_q = Core::VariableRef.new('q')
153
- goal = equals_goal(ref1_q, ref2_q)
154
- instance = RunStarExpression.new('q', goal)
155
-
156
- # (display (run* q (== q q))) ;; => (_0)
157
- # Reasoned S2, frame 1:20
158
- result = instance.run
159
- expect(result.car).to eq(any_value(0))
160
- end
161
-
162
- it 'should accept the nesting of sub-environment' do
163
- goal = equals_goal(pea, ref_q)
164
- fresh_env = FreshEnv.new(['x'], goal)
165
- instance = RunStarExpression.new('q', fresh_env)
166
-
167
- # Reasoned S2, frame 1:21..23
168
- # (run* q (fresh (x) (== 'pea q))) ;; => (pea)
169
- result = instance.run
170
-
171
- # Reasoned S2, frame 1:40
172
- expect(ref_q.different_from?(ref_x, fresh_env)).to be_truthy
173
- expect(result.car).to eq(pea)
174
- end
175
-
176
- it 'should unify nested variables' do
177
- goal = equals_goal(pea, ref_x)
178
- fresh_env = FreshEnv.new(['x'], goal)
179
- instance = RunStarExpression.new('q', fresh_env)
180
-
181
- # Reasoned S2, frame 1:24
182
- # (run* q (fresh (x) (== 'pea x))) ;; => (_0)
183
- result = instance.run
184
- expect(result.car).to eq(any_value(0))
185
- end
186
-
187
- it 'should accept expression with variables' do
188
- goal = equals_goal(cons(ref_x), ref_q)
189
- fresh_env = FreshEnv.new(['x'], goal)
190
- instance = RunStarExpression.new('q', fresh_env)
191
-
192
- # Reasoned S2, frame 1:25
193
- # (run* q (fresh (x) (== (cons x '()) q))) ;; => ((_0))
194
- result = instance.run
195
- expect(result.car).to eq(cons(any_value(0)))
196
- end
197
-
198
- it 'should accept fused variables' do
199
- goal = equals_goal(ref_x, ref_q)
200
- fresh_env = FreshEnv.new(['x'], goal)
201
- instance = RunStarExpression.new('q', fresh_env)
202
-
203
- # Reasoned S2, frame 1:31
204
- # (run* q (fresh (x) (== x q))) ;; => (_0)
205
- result = instance.run
206
- expect(ref_q.fresh?(instance.env)).to be_truthy
207
- expect(ref_x.fresh?(fresh_env)).to be_truthy
208
-
209
- # q should be fused with x...
210
- expect(ref_q.fused_with?(ref_x, fresh_env)).to be_truthy
211
- expect(ref_q.names_fused(fresh_env)).to eq(['x'])
212
- expect(ref_x.names_fused(fresh_env)).to eq(['q'])
213
- expect(result.car).to eq(any_value(0))
214
- end
215
-
216
- it 'should cope with complex equality expressions' do
217
- expr1 = cons(cons(cons(pea)), pod)
218
- expr2 = cons(cons(cons(pea)), pod)
219
- goal = equals_goal(expr1, expr2)
220
- instance = RunStarExpression.new('q', goal)
221
-
222
- # Reasoned S2, frame 1:32
223
- # (run* q (== '(((pea)) pod) '(((pea)) pod))) ;; => (_0)
224
- result = instance.run
225
- expect(result.car).to eq(any_value(0))
125
+ expect(instance.run.to_s).to eq('(_0)')
226
126
  end
227
127
 
228
- it 'should unify complex equality expressions (I)' do
229
- expr1 = cons(cons(cons(pea)), pod)
230
- expr2 = cons(cons(cons(pea)), ref_q)
231
- goal = equals_goal(expr1, expr2)
232
- instance = RunStarExpression.new('q', goal)
233
-
234
- # Beware: quasiquoting
235
- # Reasoned S2, frame 1:33
236
- # (run* q (== '(((pea)) pod) `(((pea)) ,q))) ;; => ('pod)
237
- result = instance.run
238
- expect(result.car).to eq(pod)
239
- end
240
-
241
- it 'should unify complex equality expressions (II)' do
242
- expr1 = cons(cons(cons(ref_q)), pod)
243
- expr2 = cons(cons(cons(pea)), pod)
244
- goal = equals_goal(expr1, expr2)
245
- instance = RunStarExpression.new('q', goal)
246
-
247
- # Reasoned S2, frame 1:34
248
- # (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pea)
249
- result = instance.run
250
- expect(result.car).to eq(pea)
251
- end
252
-
253
- it 'should unify complex equality expressions (III)' do
254
- expr1 = cons(cons(cons(ref_q)), pod)
255
- expr2 = cons(cons(cons(ref_x)), pod)
256
- goal = equals_goal(expr1, expr2)
257
- fresh_env = FreshEnv.new(['x'], goal)
258
- instance = RunStarExpression.new('q', fresh_env)
259
-
260
- # Reasoned S2, frame 1:35
261
- # (run* q (fresh (x) (== '(((,q)) pod) `(((,x)) pod)))) ;; => (_0)
262
- result = instance.run
263
- expect(result.car).to eq(any_value(0))
264
- end
265
-
266
- it 'should unify complex equality expressions (IV)' do
267
- # Reasoned S2, frame 1:36
268
- # (run* q (fresh (x) (== '(((,q)) (,x)) `(((,x)) pod)))) ;; => ('pod)
269
- expr1 = cons(cons(cons(ref_q)), cons(ref_x))
270
- expr2 = cons(cons(cons(ref_x)), cons(pod))
271
- goal = equals_goal(expr1, expr2)
272
- fresh_env = FreshEnv.new(['x'], goal)
273
- instance = RunStarExpression.new('q', fresh_env)
274
-
275
- result = instance.run
276
- expect(result.car).to eq(pod)
277
- end
278
-
279
- it 'should unify with repeated fresh variable' do
280
- # Reasoned S2, frame 1:37
281
- # (run* q (fresh (x) (== '( ,x ,x) q))) ;; => (_0 _0)
282
- expr1 = cons(ref_x, cons(ref_x))
283
- goal = equals_goal(expr1, ref_q)
284
- fresh_env = FreshEnv.new(['x'], goal)
285
- instance = RunStarExpression.new('q', fresh_env)
286
-
287
- result = instance.run
288
- expect(result.car).to eq(cons(any_value(0), cons(any_value(0))))
289
- end
290
-
291
- it 'should unify multiple times' do
292
- # Reasoned S2, frame 1:38
293
- # (run* q (fresh (x) (fresh (y) (== '( ,q ,y) '((,x ,y) ,x))))) ;; => (_0 _0)
294
- expr1 = cons(ref_q, cons(ref_y))
295
- expr2 = cons(cons(ref_x, cons(ref_y)), cons(ref_x))
296
- goal = equals_goal(expr1, expr2)
297
- fresh_env_y = FreshEnv.new(['y'], goal)
298
- fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
299
- instance = RunStarExpression.new('q', fresh_env_x)
300
-
301
- result = instance.run
302
-
303
- # y should be fused with x...
304
- var_x = fresh_env_y.name2var('x')
305
- var_y = fresh_env_y.name2var('y')
306
- expect(var_x.i_name).to eq(var_y.i_name)
307
- expect(ref_y.fused_with?(ref_x, fresh_env_y)).to be_truthy
308
- expect(ref_x.names_fused(fresh_env_y)).to eq(['y'])
309
- expect(ref_y.names_fused(fresh_env_y)).to eq(['x'])
310
-
311
- # q should be bound to '(,x ,x)
312
- expect(result.car).to eq(cons(any_value(0), cons(any_value(0))))
313
- end
314
-
315
- it 'should support multiple fresh variables' do
316
- # Reasoned S2, frame 1:41
317
- # (run* q (fresh (x) (fresh (y) (== '( ,x ,y) q)))) ;; => (_0 _1)
318
- expr1 = cons(ref_x, cons(ref_y))
319
- goal = equals_goal(expr1, ref_q)
320
- fresh_env_y = FreshEnv.new(['y'], goal)
321
- fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
322
- instance = RunStarExpression.new('q', fresh_env_x)
128
+ it 'should return a value with a succeeding goal and q bound' do
129
+ # Reasoned S2, frame 1:11
130
+ # (run* q (== q 'pea)) ;; => (pea)
131
+ instance = RunStarExpression.new('q', unify(ref_q, pea))
323
132
 
324
- result = instance.run
325
- # q should be bound to '(,x ,y)
326
- expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
133
+ expect(instance.run.to_s).to eq('(:pea)')
327
134
  end
328
135
 
329
- it 'should work with variable names' do
330
- # Reasoned S2, frame 1:42
331
- # (run* s (fresh (t) (fresh (u) (== '( ,t ,u) s)))) ;; => (_0 _1)
332
- expr1 = cons(ref_t, cons(ref_u))
333
- goal = equals_goal(expr1, ref_s)
334
- fresh_env_u = FreshEnv.new(['u'], goal)
335
- fresh_env_t = FreshEnv.new(['t'], fresh_env_u)
336
- instance = RunStarExpression.new('s', fresh_env_t)
136
+ it 'should return a _0 with a succeeding goal and q fresh' do
137
+ # Reasoned S2, frame 1:11
138
+ # (run* q (== q q)) ;; => (_0)
139
+ instance = RunStarExpression.new('q', unify(ref_q, ref_q))
337
140
 
338
- result = instance.run
339
- # s should be bound to '(,t ,u)
340
- expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
141
+ expect(instance.run.to_s).to eq('(_0)')
341
142
  end
342
143
 
343
- it 'should support repeated variables' do
344
- # Reasoned S2, frame 1:43
345
- # (run* q (fresh (x) (fresh (y) (== '( ,x ,y ,x) q)))) ;; => (_0 _1 _0)
346
- expr1 = cons(ref_x, cons(ref_y, cons(ref_x)))
347
- goal = equals_goal(expr1, ref_q)
348
- fresh_env_y = FreshEnv.new(['y'], goal)
349
- fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
350
- instance = RunStarExpression.new('q', fresh_env_x)
144
+ it 'should support the fresh form to nest scopes' do
145
+ # Reasoned S2, frame 1:21
146
+ # (run* q (fresh (x) (== 'pea q))) ;; => (pea)
147
+ subgoal = unify(pea, ref_q)
148
+ instance = RunStarExpression.new('q', fresh('x', subgoal))
351
149
 
352
- result = instance.run
353
- # q should be bound to '(,x ,y, ,x)
354
- expect(result.car).to eq(cons(any_value(0), cons(any_value(1), cons(any_value(0)))))
150
+ expect(instance.run.to_s).to eq('(:pea)')
355
151
  end
356
152
 
357
153
  it 'should support conjunction of two succeed' do
358
- goal = conj2_goal(succeeds, succeeds)
359
- instance = RunStarExpression.new('q', goal)
360
-
361
154
  # Reasoned S2, frame 1:50
362
155
  # (run* q (conj2 succeed succeed)) ;; => (_0)
156
+ goal = conj2(succeeds, succeeds)
157
+ instance = RunStarExpression.new('q', goal)
158
+
363
159
  result = instance.run
364
- expect(result.car).to eq(any_value(0))
160
+ expect(result.to_s).to eq('(_0)')
365
161
  end
366
162
 
367
163
  it 'should support conjunction of one succeed and a successful goal' do
368
- subgoal = equals_goal(corn, ref_q)
369
- goal = conj2_goal(succeeds, subgoal)
370
- instance = RunStarExpression.new('q', goal)
371
-
372
164
  # Reasoned S2, frame 1:51
373
165
  # (run* q (conj2 succeed (== 'corn q)) ;; => ('corn)
374
- result = instance.run
375
- expect(result.car).to eq(corn)
376
- end
377
-
378
- it 'should support conjunction of one fail and a successful goal' do
379
- subgoal = equals_goal(corn, ref_q)
380
- goal = conj2_goal(fails, subgoal)
381
- instance = RunStarExpression.new('q', goal)
382
-
383
- # Reasoned S2, frame 1:52
384
- # (run* q (conj2 fail (== 'corn q)) ;; => ()
385
- expect(instance.run).to be_null
386
- end
387
-
388
- it 'should support conjunction of two contradictory goals' do
389
- subgoal1 = equals_goal(corn, ref_q)
390
- subgoal2 = equals_goal(meal, ref_q)
391
- goal = conj2_goal(subgoal1, subgoal2)
392
- instance = RunStarExpression.new('q', goal)
393
-
394
- # Reasoned S2, frame 1:53
395
- # (run* q (conj2 (== 'corn q)(== 'meal q)) ;; => ()
396
- expect(instance.run).to be_null
397
- end
398
-
399
- it 'should succeed the conjunction of two identical goals' do
400
- subgoal1 = equals_goal(corn, ref_q)
401
- subgoal2 = equals_goal(corn, ref_q)
402
- goal = conj2_goal(subgoal1, subgoal2)
403
- instance = RunStarExpression.new('q', goal)
166
+ subgoal = unify(corn, ref_q)
167
+ instance = RunStarExpression.new('q', conj2(succeeds, subgoal))
404
168
 
405
- # Reasoned S2, frame 1:54
406
- # (run* q (conj2 (== 'corn q)(== 'corn q)) ;; => ('corn)
407
169
  result = instance.run
408
- expect(result.car).to eq(corn)
170
+ expect(result.to_s).to eq('(:corn)')
409
171
  end
410
172
 
411
- it 'should not yield solution when both disjunction arguments fail' do
412
- goal = disj2_goal(fails, fails)
413
- instance = RunStarExpression.new('q', goal)
414
-
415
- # Reasoned S2, frame 1:55
416
- # (run* q (disj2 fail fail)) ;; => ()
417
- expect(instance.run).to be_null
418
- end
419
-
420
- it 'should yield solution when first argument succeed' do
421
- subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
422
- goal = disj2_goal(subgoal, fails)
423
- instance = RunStarExpression.new('q', goal)
424
-
425
- # Reasoned S2, frame 1:56
426
- # (run* q (disj2 (== 'olive q) fail)) ;; => ('olive)
427
- result = instance.run
428
- expect(result.car).to eq(olive)
429
- end
430
-
431
- it 'should yield solution when second argument succeed' do
432
- subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
433
- goal = disj2_goal(fails, subgoal)
434
- instance = RunStarExpression.new('q', goal)
435
-
436
- # Reasoned S2, frame 1:57
437
- # (run* q (disj2 fail (== 'oil q))) ;; => (oil)
438
- result = instance.run
439
- expect(result.car).to eq(oil)
440
- end
441
-
442
- it 'should yield solutions when both arguments succeed' do
443
- subgoal1 = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
444
- subgoal2 = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
445
- goal = disj2_goal(subgoal1, subgoal2)
446
- instance = RunStarExpression.new('q', goal)
447
-
448
- # Reasoned S2, frame 1:58
449
- # (run* q (disj2 (== 'olive q) (== 'oil q))) ;; => (olive oil)
450
- result = instance.run
451
- expect(result.car).to eq(olive)
452
- expect(result.cdr.car).to eq(oil)
453
- end
454
-
455
- it 'should support the nesting of variables and disjunction' do
456
- # Reasoned S2, frame 1:59
457
- # (run* q (fresh (x) (fresh (y) (disj2 (== '( ,x ,y ) q) (== '( ,x ,y ) q)))))
458
- # ;; => ((_0 _1) (_0 _1))
459
- expr1 = cons(ref_x, cons(ref_y))
460
- subgoal1 = equals_goal(expr1, ref_q)
461
- expr2 = cons(ref_y, cons(ref_x))
462
- subgoal2 = equals_goal(expr2, ref_q)
463
- goal = disj2_goal(subgoal1, subgoal2)
464
- fresh_env_y = FreshEnv.new(['y'], goal)
465
- fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
466
- instance = RunStarExpression.new('q', fresh_env_x)
467
-
468
- result = instance.run
469
- # q should be bound to '(,x ,y), then to '(,y ,x)
470
- expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
471
- expect(result.cdr.car).to eq(cons(any_value(0), cons(any_value(1))))
472
- end
473
-
474
- it 'should accept nesting of disj2 and conj2 (I)' do
475
- conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
476
- conjunction = conj2_goal(conj_subgoal, fails)
477
- subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
478
- goal = disj2_goal(conjunction, subgoal)
479
- instance = RunStarExpression.new('x', goal)
480
-
481
- # Reasoned S2, frame 1:62
482
- # (run* x (disj2
483
- # (conj2 (== 'olive x) fail)
484
- # (== 'oil x))) ;; => (oil)
485
- result = instance.run
486
- expect(result.car).to eq(oil)
487
- end
488
-
489
- it 'should accept nesting of disj2 and conj2 (II)' do
490
- conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
491
- conjunction = conj2_goal(conj_subgoal, succeeds)
492
- subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
493
- goal = disj2_goal(conjunction, subgoal)
494
- instance = RunStarExpression.new('x', goal)
495
-
496
- # Reasoned S2, frame 1:63
497
- # (run* x (disj2
498
- # (conj2 (== 'olive x) succeed)
499
- # ('oil x))) ;; => (olive oil)
500
- result = instance.run
501
- expect(result.car).to eq(olive)
502
- expect(result.cdr.car).to eq(oil)
503
- end
504
-
505
- it 'should accept nesting of disj2 and conj2 (III)' do
506
- conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
507
- conjunction = conj2_goal(conj_subgoal, succeeds)
508
- subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
509
- goal = disj2_goal(subgoal, conjunction)
510
- instance = RunStarExpression.new('x', goal)
511
-
512
- # Reasoned S2, frame 1:64
513
- # (run* x (disj2
514
- # (== 'oil x)
515
- # (conj2 (== 'olive x) succeed))) ;; => (oil olive)
516
- result = instance.run
517
- expect(result.car).to eq(oil)
518
- expect(result.cdr.car).to eq(olive)
519
- end
520
-
521
- it 'should accept nesting of disj2 and conj2 (IV)' do
522
- oil_goal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
523
- disja = disj2_goal(succeeds, oil_goal)
524
- olive_goal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
525
- disjb = disj2_goal(olive_goal, disja)
526
- virgin_goal = Core::Goal.new(Core::Equals.instance, [virgin, ref_x])
527
- conjunction = conj2_goal(virgin_goal, fails)
528
- goal = disj2_goal(conjunction, disjb)
529
- instance = RunStarExpression.new('x', goal)
530
-
531
- # Reasoned S2, frame 1:65
532
- # (run* x (disj2
533
- # (conj2(== 'virgin x) fail)
534
- # (disj2
535
- # (== 'olive x)
536
- # (dis2
537
- # succeed
538
- # (== 'oil x))))) ;; => (olive _0 oil)
539
- result = instance.run
540
- expect(result.car).to eq(olive)
541
- expect(result.cdr.car).to eq(any_value(0))
542
- expect(result.cdr.cdr.car).to eq(oil)
543
- end
544
-
545
- it 'should accept nesting fresh, disj2 and conj2 expressions (I)' do
546
- subgoal1 = equals_goal(split, ref_x)
547
- expr1 = equals_goal(pea, ref_y)
548
- expr2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
549
- subgoal2 = conj2_goal(expr1, expr2)
550
- goal = conj2_goal(subgoal1, subgoal2)
551
- fresh_env_y = FreshEnv.new(['y'], goal)
552
- fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
553
- instance = RunStarExpression.new('r', fresh_env_x)
554
-
555
- # Reasoned S2, frame 1:67
556
- # (run* r
557
- # (fresh x
558
- # (fresh y
559
- # (conj2
560
- # (== 'split x)
561
- # (conj2
562
- # (== 'pea y)
563
- # (== '(,x ,y) r)))))) ;; => ((split pea))
564
- result = instance.run
565
- expect(result.car.car).to eq(split)
566
- expect(result.car.cdr.car).to eq(pea)
567
- end
568
-
569
- it 'should accept nesting fresh, disj2 and conj2 expressions (II)' do
570
- expr1 = equals_goal(split, ref_x)
571
- expr2 = equals_goal(pea, ref_y)
572
- subgoal1 = conj2_goal(expr1, expr2)
573
- subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
574
- goal = conj2_goal(subgoal1, subgoal2)
575
- fresh_env_y = FreshEnv.new(['y'], goal)
576
- fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
577
- instance = RunStarExpression.new('r', fresh_env_x)
578
-
579
- # Reasoned S2, frame 1:68
580
- # (run* r
581
- # (fresh x
582
- # (fresh y
583
- # (conj2
584
- # (conj2
585
- # (== 'split x)
586
- # (== 'pea y)
587
- # (== '(,x ,y) r)))))) ;; => ((split pea))
588
- result = instance.run
589
- expect(result.car.car).to eq(split)
590
- expect(result.car.cdr.car).to eq(pea)
591
- end
592
-
593
- it 'should accept fresh with multiple variables' do
594
- expr1 = equals_goal(split, ref_x)
595
- expr2 = equals_goal(pea, ref_y)
596
- subgoal1 = conj2_goal(expr1, expr2)
597
- subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
598
- goal = conj2_goal(subgoal1, subgoal2)
599
- fresh_env = FreshEnv.new(%w[x y], goal)
600
- instance = RunStarExpression.new('r', fresh_env)
601
-
602
- # Reasoned S2, frame 1:70
603
- # (run* r
604
- # (fresh (x y)
605
- # (conj2
606
- # (conj2
607
- # (== 'split x)
608
- # (== 'pea y)
609
- # (== '(,x ,y) r))))) ;; => ((split pea))
610
- result = instance.run
611
- expect(result.car.car).to eq(split)
612
- expect(result.car.cdr.car).to eq(pea)
613
- end
614
-
615
- it 'should accept multiple variables' do
616
- expr1 = equals_goal(split, ref_x)
617
- expr2 = equals_goal(pea, ref_y)
618
- subgoal1 = conj2_goal(expr1, expr2)
619
- subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
620
- goal = conj2_goal(subgoal1, subgoal2)
621
- instance = RunStarExpression.new(%w[r x y], goal)
622
-
623
- # Reasoned S2, frame 1:72
624
- # (run* (r x y)
625
- # (conj2
626
- # (conj2
627
- # (== 'split x)
628
- # (== 'pea y))
629
- # (== '(,x ,y) r))) ;; => (((split pea) split pea))
630
- # o
631
- # / \
632
- # o nil
633
- # / \
634
- # / \
635
- # / \
636
- # / \
637
- # / \
638
- # o o
639
- # / \ / \
640
- # split o split o
641
- # / \ / \
642
- # pea nil pea nil
643
- result = instance.run
644
- expect(result.car.car.car).to eq(split)
645
- expect(result.car.car.cdr.car).to eq(pea)
646
- expect(result.car.car.cdr.cdr).to be_nil
647
- expect(result.car.cdr.car).to eq(split)
648
- expect(result.car.cdr.cdr.car).to eq(pea)
649
- expect(result.car.cdr.cdr.cdr).to be_nil
650
- end
651
-
652
- it 'should allow simplification of expressions' do
653
- expr1 = equals_goal(split, ref_x)
654
- expr2 = equals_goal(pea, ref_y)
655
- goal = conj2_goal(expr1, expr2)
656
- instance = RunStarExpression.new(%w[x y], goal)
657
-
658
- # Reasoned S2, frame 1:75
659
- # (run* (x y)
660
- # (conj2
661
- # (== 'split x)
662
- # (== 'pea y))) ;; => ((split pea))
663
- result = instance.run
664
- expect(result.car.car).to eq(split)
665
- expect(result.car.cdr.car).to eq(pea)
666
- end
667
-
668
- it 'should allow simplication of expressions' do
669
- expr1 = equals_goal(split, ref_x)
670
- expr2 = equals_goal(pea, ref_y)
671
- subgoal1 = conj2_goal(expr1, expr2)
672
- expr3 = equals_goal(red, ref_x)
673
- expr4 = equals_goal(bean, ref_y)
674
- subgoal2 = conj2_goal(expr3, expr4)
675
- goal = disj2_goal(subgoal1, subgoal2)
676
- instance = RunStarExpression.new(%w[x y], goal)
677
-
678
- # Reasoned S2, frame 1:76
679
- # (run* (x y)
680
- # (disj2
681
- # (conj2 (== 'split x) (== 'pea y))
682
- # (conj2 (== 'red x) (== 'bean y)))) ;; => ((split pea)(red bean))
683
- result = instance.run
684
- expect(result.car.car).to eq(split)
685
- expect(result.car.cdr.car).to eq(pea)
686
- expect(result.cdr.car.car).to eq(red)
687
- expect(result.cdr.car.cdr.car).to eq(bean)
688
- end
689
-
690
- it 'should allow nesting a disjunction inside of conjunction' do
691
- expr1 = equals_goal(split, ref_x)
692
- expr2 = equals_goal(red, ref_x)
693
- subgoal1 = disj2_goal(expr1, expr2)
694
- subgoal2 = equals_goal(ref_x, ref_y)
695
- goal = conj2_goal(subgoal1, subgoal2)
696
- instance = RunStarExpression.new(%w[x y], goal)
697
-
698
- # (display (run* (x y)
699
- # (conj2
700
- # (disj2
701
- # (== 'split x)
702
- # (== 'red x))
703
- # (== x y)))) ;; => ((split split) (red red))
704
- result = instance.run
705
- expect(result.car.car).to eq(split)
706
- expect(result.car.cdr.car).to eq(split)
707
- expect(result.cdr.car.cdr.car).to eq(red)
708
- end
709
-
710
- it 'should accept fresh with multiple variables' do
711
- expr1 = equals_goal(split, ref_x)
712
- expr2 = equals_goal(pea, ref_y)
713
- subgoal1 = conj2_goal(expr1, expr2)
714
- expr3 = equals_goal(red, ref_x)
715
- expr4 = equals_goal(bean, ref_y)
716
- subgoal2 = conj2_goal(expr3, expr4)
717
- subgoal3 = disj2_goal(subgoal1, subgoal2)
718
- subgoal4 = equals_goal(cons(ref_x, cons(ref_y, cons(soup))), ref_r)
719
- goal = conj2_goal(subgoal3, subgoal4)
720
- fresh_env = FreshEnv.new(%w[x y], goal)
721
- instance = RunStarExpression.new('r', fresh_env)
722
-
723
- # Reasoned S2, frame 1:77
724
- # (run* r
725
- # (fresh (x y)
726
- # (conj2
727
- # (disj2
728
- # (conj2 (== 'split x) (== 'pea y))
729
- # (conj2 (== 'red x) (== 'bean y)))
730
- # (== '(,x ,y soup) r)))) ;; => ((split pea soup) (red bean soup))
731
- result = instance.run
732
- expect(result.car.car).to eq(split)
733
- expect(result.car.cdr.car).to eq(pea)
734
- expect(result.car.cdr.cdr.car).to eq(soup)
735
- expect(result.cdr.car.car).to eq(red)
736
- expect(result.cdr.car.cdr.car).to eq(bean)
737
- expect(result.cdr.car.cdr.cdr.car).to eq(soup)
738
- end
739
-
740
- it 'should allow fresh with multiple goals' do
741
- expr1 = equals_goal(split, ref_x)
742
- expr2 = equals_goal(pea, ref_y)
743
- subgoal1 = conj2_goal(expr1, expr2)
744
- expr3 = equals_goal(red, ref_x)
745
- expr4 = equals_goal(bean, ref_y)
746
- subgoal2 = conj2_goal(expr3, expr4)
747
- goal1 = disj2_goal(subgoal1, subgoal2)
748
- goal2 = equals_goal(cons(ref_x, cons(ref_y, cons(soup))), ref_r)
749
- fresh_env = FreshEnv.new(%w[x y], [goal1, goal2])
750
- instance = RunStarExpression.new('r', fresh_env)
751
-
752
- # Reasoned S2, frame 1:78
753
- # (run* r
754
- # (fresh (x y)
755
- # (disj2
756
- # (conj2 (== 'split x) (== 'pea y))
757
- # (conj2 (== 'red x) (== 'bean y)))
758
- # (== '(,x ,y soup) r))) ;; => ((split pea soup) (red bean soup))
759
- result = instance.run
760
- expect(result.car.car).to eq(split)
761
- expect(result.car.cdr.car).to eq(pea)
762
- expect(result.car.cdr.cdr.car).to eq(soup)
763
- expect(result.cdr.car.car).to eq(red)
764
- expect(result.cdr.car.cdr.car).to eq(bean)
765
- expect(result.cdr.car.cdr.cdr.car).to eq(soup)
766
- end
767
-
768
- it 'should allow run* with multiple goals' do
769
- expr1 = equals_goal(split, ref_x)
770
- expr2 = equals_goal(pea, ref_y)
771
- subgoal1 = conj2_goal(expr1, expr2)
772
- expr3 = equals_goal(red, ref_x)
773
- expr4 = equals_goal(bean, ref_y)
774
- subgoal2 = conj2_goal(expr3, expr4)
775
- goal1 = disj2_goal(subgoal1, subgoal2)
776
- goal2 = equals_goal(soup, ref_z)
777
- instance = RunStarExpression.new(%w[x y z], [goal1, goal2])
778
-
779
- # Reasoned S2, frame 1:80
780
- # (run* (x y z)
781
- # (disj2
782
- # (conj2 (== 'split x) (== 'pea y))
783
- # (conj2 (== 'red x) (== 'bean y)))
784
- # (== 'soup z)) ;; => ((split pea soup) (red bean soup))
785
- result = instance.run
786
- expect(result.car.car).to eq(split)
787
- expect(result.car.cdr.car).to eq(pea)
788
- expect(result.car.cdr.cdr.car).to eq(soup)
789
- expect(result.cdr.car.car).to eq(red)
790
- expect(result.cdr.car.cdr.car).to eq(bean)
791
- expect(result.cdr.car.cdr.cdr.car).to eq(soup)
792
- end
793
-
794
- it 'should allow simplified expressions with multiple goals' do
795
- expr1 = equals_goal(split, ref_x)
796
- expr2 = equals_goal(pea, ref_y)
797
- instance = RunStarExpression.new(%w[x y], [expr1, expr2])
798
-
799
- # Reasoned S2, frame 1:81
800
- # (run* (x y)
801
- # (== 'split x)
802
- # (== 'pea y)) ;; => ((split pea))
803
- result = instance.run
804
- expect(result.car.car).to eq(split)
805
- expect(result.car.cdr.car).to eq(pea)
806
- end
807
-
808
- it 'should solve expression with defrel' do
809
- teacupo_goal = Core::Goal.new(teacupo_rel, [ref_x])
810
-
811
- # Reasoned S2, frame 1:83
812
- # (run* x
813
- # (teacupo x)) ;; => ((tea cup))
814
- instance = RunStarExpression.new('x', teacupo_goal)
815
-
816
- result = instance.run
817
- expect(result.car).to eq(tea)
818
- expect(result.cdr.car).to eq(cup)
819
- end
820
-
821
- it 'should solve expression with defrel and booleans' do
822
- teacupo_goal = Core::Goal.new(teacupo_rel, [ref_x])
823
- expr2 = equals_goal(k_true, ref_y)
824
- subgoal1 = conj2_goal(teacupo_goal, expr2)
825
- expr3 = equals_goal(k_false, ref_x)
826
- expr4 = equals_goal(k_true, ref_y)
827
- subgoal2 = conj2_goal(expr3, expr4)
828
- goal = disj2_goal(subgoal1, subgoal2)
829
- # Reasoned S2, frame 1:84
830
- # (run* (x y)
831
- # (disj2
832
- # (conj2 (teacupo x) (== #t y))
833
- # (conj2 (== #f x) (== #t y))) ;; => ((#f #t)(tea #t) (cup #t))
834
- instance = RunStarExpression.new(%w[x y], goal)
835
-
836
- result = instance.run
837
- # Order of solutions differs from RS book
838
- expect(result.car).to eq(cons(tea, cons(true)))
839
- expect(result.cdr.car).to eq(cons(cup, cons(true)))
840
- expect(result.cdr.cdr.car).to eq(cons(false, cons(true)))
841
- end
842
-
843
- it 'should solve expression with two variable and defrel' do
844
- teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
845
- teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_y])
846
-
847
- # Reasoned S2, frame 1:85
848
- # (run* (x y)
849
- # (teacupo x)
850
- # (teacupo y)) ;; => ((tea tea)(tea cup)(cup tea)(cup c))
851
- instance = RunStarExpression.new(%w[x y], [teacupo_goal1, teacupo_goal2])
852
-
853
- result = instance.run
854
- expect(result.car).to eq(cons(tea, cons(tea)))
855
- expect(result.cdr.car).to eq(cons(tea, cons(cup)))
856
- expect(result.cdr.cdr.car).to eq(cons(cup, cons(tea)))
857
- expect(result.cdr.cdr.cdr.car).to eq(cons(cup, cons(cup)))
858
- end
859
-
860
- it 'should solve expression with two variable and defrel' do
861
- teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
862
- teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_x])
863
-
864
- # Reasoned S2, frame 1:86
865
- # (run* (x y)
866
- # (teacupo x)
867
- # (teacupo x)) ;; => ((tea _0)(cup _0))
868
- instance = RunStarExpression.new(%w[x y], [teacupo_goal1, teacupo_goal2])
869
-
870
- result = instance.run
871
- expect(result.car).to eq(cons(tea, cons(any_value(0))))
872
- expect(result.cdr.car).to eq(cons(cup, cons(any_value(0))))
873
- end
874
-
875
- it 'should solve expression with defrel and booleans' do
876
- teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
877
- teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_x])
878
- subgoal1 = conj2_goal(teacupo_goal1, teacupo_goal2)
879
- expr3 = equals_goal(k_false, ref_x)
880
- expr4 = Core::Goal.new(teacupo_rel, [ref_y])
881
- subgoal2 = conj2_goal(expr3, expr4)
882
- goal = disj2_goal(subgoal1, subgoal2)
883
- # Reasoned S2, frame 1:87
884
- # (run* (x y)
885
- # (disj2
886
- # (conj2 (teacupo x) (teacupo x))
887
- # (conj2 (== #f x) (teacupo y)))) ;; => ((#f tea)(#f cup)(tea _0)(cup _0))
888
- instance = RunStarExpression.new(%w[x y], goal)
889
-
890
- result = instance.run
891
- # Order of solutions differs from RS book
892
- expect(result.car).to eq(cons(tea, cons(any_value(0))))
893
- expect(result.cdr.car).to eq(cons(cup, cons(any_value(0))))
894
- expect(result.cdr.cdr.car).to eq(cons(false, cons(tea)))
895
- expect(result.cdr.cdr.cdr.car).to eq(cons(false, cons(cup)))
896
- end
897
-
898
- it 'should allow conde in the goal expression' do
899
- teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
900
- teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_x])
901
- expr3 = equals_goal(k_false, ref_x)
902
- expr4 = Core::Goal.new(teacupo_rel, [ref_y])
903
- goal = conde_goal([[teacupo_goal1, teacupo_goal2], [expr3, expr4]])
904
- # Reasoned S2, frame 1:88
905
- # (run* (x y)
906
- # (conde
907
- # ((teacupo x) (teacupo x))
908
- # ((== #f x) (teacupo y)))) ;; => ((#f tea)(#f cup)(tea _0)(cup _0))
909
- instance = RunStarExpression.new(%w[x y], goal)
910
-
911
- result = instance.run
912
- expect(result.car).to eq(cons(tea, cons(any_value(0))))
913
- expect(result.cdr.car).to eq(cons(cup, cons(any_value(0))))
914
- expect(result.cdr.cdr.car).to eq(cons(false, cons(tea)))
915
- expect(result.cdr.cdr.cdr.car).to eq(cons(false, cons(cup)))
916
- end
917
-
918
- it 'should allow simplication of expressions (conde version)' do
919
- expr1 = equals_goal(split, ref_x)
920
- expr2 = equals_goal(pea, ref_y)
921
- combo1 = [expr1, expr2]
922
- expr3 = equals_goal(red, ref_x)
923
- expr4 = equals_goal(bean, ref_y)
924
- combo2 = [expr3, expr4]
925
- goal = conde_goal([combo1, combo2])
926
- instance = RunStarExpression.new(%w[x y], goal)
927
-
928
- # Reasoned S2, frame 1:88 (second part, a rewrite of 1:76)
929
- # (run* (x y)
930
- # (conde
931
- # ((== 'split x) (== 'pea y))
932
- # ((== 'red x) (== 'bean y)))) ;; => ((split pea)(red bean))
933
- result = instance.run
934
- expect(result.car.car).to eq(split)
935
- expect(result.car.cdr.car).to eq(pea)
936
- expect(result.cdr.car.car).to eq(red)
937
- expect(result.cdr.car.cdr.car).to eq(bean)
938
- end
939
-
940
- it 'should accept nesting of disj2 and conj2 (conde version)' do
941
- equals_olive = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
942
- combo = [equals_olive, fails]
943
- equals_oil = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
944
- goal = conde_goal([combo, equals_oil])
945
- instance = RunStarExpression.new('x', goal)
946
-
947
- # Reasoned S2, frame 1:89 (rewrite of 1:62)
948
- # (run* x
949
- # (conde
950
- # ((== 'olive x) fail)
951
- # ('oil x))) ;; => (oil)
952
- result = instance.run
953
- expect(result.car).to eq(oil)
954
- end
955
-
956
- it 'should accept nesting of conde inside a fresh context' do
957
- equals_lentil = Core::Goal.new(Core::Equals.instance, [lentil, ref_z])
958
- fresh_env = FreshEnv.new(['z'], equals_lentil)
959
- equals_xy = Core::Goal.new(Core::Equals.instance, [ref_x, ref_y])
960
- goal = conde_goal([fresh_env, equals_xy])
961
- instance = RunStarExpression.new(%w[x y], goal)
962
- fresh_env.parent = instance.env
963
-
964
- # Reasoned S2, frame 1:90
965
- # (run* (x y)
966
- # (conde
967
- # ((fresh (z)
968
- # (== 'lentil z)))
969
- # ((== x y)))) ;; => ((_0 _1)(_0 _0))
970
- result = instance.run
971
- expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
972
- expect(result.cdr.car).to eq(cons(any_value(0), cons(any_value(0))))
973
- end
974
-
975
- it 'accepts conde with more than two condition lines' do
976
- expr1 = equals_goal(split, ref_x)
977
- expr2 = equals_goal(pea, ref_y)
978
- combo1 = [expr1, expr2]
979
- expr3 = equals_goal(red, ref_x)
980
- expr4 = equals_goal(bean, ref_y)
981
- combo2 = [expr3, expr4]
982
- expr5 = equals_goal(green, ref_x)
983
- expr6 = equals_goal(lentil, ref_y)
984
- combo3 = [expr5, expr6]
985
- goal = conde_goal([combo1, combo2, combo3])
986
- instance = RunStarExpression.new(%w[x y], goal)
987
-
988
- # Reasoned S2, frame 1:91
989
- # (run* (x y)
990
- # (conde
991
- # ((== 'split x) (== 'pea y))
992
- # ((== 'red x) (== 'bean y))
993
- # ((== 'green x) (== 'lentil y))))
994
- # ;; => ((split pea)(red bean)(green lentil))
995
- result = instance.run
996
- expect(result.car).to eq(cons(split, cons(pea)))
997
- expect(result.cdr.car).to eq(cons(red, cons(bean)))
998
- expect(result.cdr.cdr.car).to eq(cons(green, cons(lentil)))
999
- end
173
+ # TODO: add two solutions case
174
+ # TODO: add fused variables
1000
175
  end # context
1001
176
  end # describe
1002
177
  end # module