mini_kraken 0.1.03 → 0.1.08

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -1
  3. data/CHANGELOG.md +54 -3
  4. data/Gemfile +3 -1
  5. data/README.md +22 -1
  6. data/Rakefile +5 -3
  7. data/lib/mini_kraken.rb +3 -1
  8. data/lib/mini_kraken/core/any_value.rb +9 -7
  9. data/lib/mini_kraken/core/association.rb +20 -7
  10. data/lib/mini_kraken/core/association_walker.rb +5 -1
  11. data/lib/mini_kraken/core/atomic_term.rb +5 -3
  12. data/lib/mini_kraken/core/binary_relation.rb +8 -6
  13. data/lib/mini_kraken/core/composite_goal.rb +46 -0
  14. data/lib/mini_kraken/core/composite_term.rb +7 -20
  15. data/lib/mini_kraken/core/conj2.rb +77 -0
  16. data/lib/mini_kraken/core/cons_cell.rb +51 -41
  17. data/lib/mini_kraken/core/designation.rb +55 -0
  18. data/lib/mini_kraken/core/disj2.rb +71 -0
  19. data/lib/mini_kraken/core/duck_fiber.rb +4 -2
  20. data/lib/mini_kraken/core/environment.rb +25 -11
  21. data/lib/mini_kraken/core/equals.rb +128 -189
  22. data/lib/mini_kraken/core/fail.rb +20 -14
  23. data/lib/mini_kraken/core/freshness.rb +11 -8
  24. data/lib/mini_kraken/core/goal.rb +8 -4
  25. data/lib/mini_kraken/core/goal_arg.rb +10 -0
  26. data/lib/mini_kraken/core/goal_relation.rb +28 -0
  27. data/lib/mini_kraken/core/k_integer.rb +4 -3
  28. data/lib/mini_kraken/core/k_symbol.rb +4 -3
  29. data/lib/mini_kraken/core/nullary_relation.rb +3 -1
  30. data/lib/mini_kraken/core/outcome.rb +29 -25
  31. data/lib/mini_kraken/core/relation.rb +4 -18
  32. data/lib/mini_kraken/core/succeed.rb +20 -14
  33. data/lib/mini_kraken/core/term.rb +7 -2
  34. data/lib/mini_kraken/core/variable.rb +11 -25
  35. data/lib/mini_kraken/core/variable_ref.rb +12 -59
  36. data/lib/mini_kraken/core/vocabulary.rb +267 -48
  37. data/lib/mini_kraken/glue/fresh_env.rb +5 -3
  38. data/lib/mini_kraken/glue/run_star_expression.rb +18 -8
  39. data/lib/mini_kraken/version.rb +3 -1
  40. data/mini_kraken.gemspec +15 -13
  41. data/spec/core/association_spec.rb +4 -4
  42. data/spec/core/association_walker_spec.rb +25 -24
  43. data/spec/core/conj2_spec.rb +114 -0
  44. data/spec/core/cons_cell_spec.rb +12 -3
  45. data/spec/core/disj2_spec.rb +99 -0
  46. data/spec/core/duck_fiber_spec.rb +22 -12
  47. data/spec/core/environment_spec.rb +16 -28
  48. data/spec/core/equals_spec.rb +7 -7
  49. data/spec/core/fail_spec.rb +7 -7
  50. data/spec/core/goal_spec.rb +10 -10
  51. data/spec/core/k_symbol_spec.rb +5 -6
  52. data/spec/core/succeed_spec.rb +4 -4
  53. data/spec/core/variable_ref_spec.rb +0 -4
  54. data/spec/core/vocabulary_spec.rb +33 -27
  55. data/spec/glue/fresh_env_spec.rb +1 -1
  56. data/spec/glue/run_star_expression_spec.rb +213 -60
  57. data/spec/mini_kraken_spec.rb +4 -0
  58. data/spec/spec_helper.rb +3 -2
  59. data/spec/support/factory_methods.rb +20 -2
  60. metadata +12 -2
@@ -15,7 +15,7 @@ module MiniKraken
15
15
  let(:pea) { Core::KSymbol.new(:pea) }
16
16
  let(:pod) { Core::KSymbol.new(:pod) }
17
17
  let(:sample_goal) do
18
- Core::Goal.new(Core::Equals.instance, [pea, pod])
18
+ Core::Goal.new(Core::Equals.instance, [pea, pod])
19
19
  end
20
20
  subject { FreshEnv.new(['q'], sample_goal) }
21
21
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  require_relative '../spec_helper' # Use the RSpec framework
4
4
  require_relative '../../lib/mini_kraken/core/goal'
5
+ require_relative '../../lib/mini_kraken/core/conj2'
6
+ require_relative '../../lib/mini_kraken/core/disj2'
5
7
  require_relative '../../lib/mini_kraken/core/equals'
6
8
  require_relative '../../lib/mini_kraken/core/fail'
7
9
  require_relative '../../lib/mini_kraken/core/succeed'
@@ -37,24 +39,30 @@ module MiniKraken
37
39
  end # context
38
40
 
39
41
  context 'Provided services:' do
42
+ let(:corn) { k_symbol(:corn) }
43
+ let(:meal) { k_symbol(:meal) }
44
+ let(:oil) { k_symbol(:oil) }
45
+ let(:olive) { k_symbol(:olive) }
46
+ let(:virgin) { k_symbol(:virgin) }
40
47
  let(:ref_q) { Core::VariableRef.new('q') }
41
48
  let(:ref_x) { Core::VariableRef.new('x') }
42
49
  let(:ref_y) { Core::VariableRef.new('y') }
43
50
  let(:ref_s) { Core::VariableRef.new('s') }
44
51
  let(:ref_t) { Core::VariableRef.new('t') }
45
- let(:ref_u) { Core::VariableRef.new('u') }
52
+ let(:ref_u) { Core::VariableRef.new('u') }
53
+ let(:fails) { Core::Goal.new(Core::Fail.instance, []) }
54
+ let(:succeeds) { Core::Goal.new(Core::Succeed.instance, []) }
46
55
 
47
- it "should return a null list with the fail goal" do
56
+ it 'should return a null list with the fail goal' do
48
57
  # Reasoned S2, frame 1:7
49
58
  # (run* q #u) ;; => ()
50
59
  failing = Core::Goal.new(Core::Fail.instance, [])
51
60
  instance = RunStarExpression.new('q', failing)
52
61
 
53
62
  expect(instance.run).to be_null
54
- expect(ref_q.fresh?(instance.env)).to be_truthy
55
63
  end
56
64
 
57
- it "should return a null list when a goal fails" do
65
+ it 'should return a null list when a goal fails' do
58
66
  # Reasoned S2, frame 1:10
59
67
  # (run* q (== 'pea 'pod) ;; => ()
60
68
 
@@ -69,7 +77,6 @@ module MiniKraken
69
77
  # Reasoned S2, frame 1:11
70
78
  # (run* q (== q 'pea) ;; => (pea)
71
79
  expect(instance.run.car).to eq(pea)
72
- expect(ref_q.fresh?(instance.env)).to be_falsey
73
80
  end
74
81
 
75
82
  it 'should unify the righthand variable(s)' do
@@ -79,19 +86,14 @@ module MiniKraken
79
86
  # Reasoned S2, frame 1:12
80
87
  # (run* q (== 'pea q) ;; => (pea)
81
88
  expect(instance.run.car).to eq(pea)
82
-
83
- # Reasoned S2, frame 1:15
84
- expect(ref_q.fresh?(instance.env)).to be_falsey
85
89
  end
86
90
 
87
91
  it 'should return a null list with the succeed goal' do
88
- success = Core::Goal.new(Core::Succeed.instance, [])
89
- instance = RunStarExpression.new('q', success)
92
+ instance = RunStarExpression.new('q', succeeds)
90
93
 
91
94
  # (display (run* q succeed)) ;; => (_0)
92
95
  # Reasoned S2, frame 1:16
93
96
  result = instance.run
94
- expect(ref_q.fresh?(instance.env)).to be_truthy
95
97
 
96
98
  # Reasoned S2, frame 1:17
97
99
  expect(result.car).to eq(any_value(0))
@@ -104,11 +106,10 @@ module MiniKraken
104
106
  # (display (run* q (== 'pea 'pea))) ;; => (_0)
105
107
  # Reasoned S2, frame 1:19
106
108
  result = instance.run
107
- expect(ref_q.fresh?(instance.env)).to be_truthy
108
109
  expect(result.car).to eq(any_value(0))
109
110
  end
110
111
 
111
- it 'should keep variable fresh when no unification occurs (III)' do
112
+ it 'should keep variable fresh when no unification occurs (II)' do
112
113
  ref1_q = Core::VariableRef.new('q')
113
114
  ref2_q = Core::VariableRef.new('q')
114
115
  goal = equals_goal(ref1_q, ref2_q)
@@ -117,7 +118,6 @@ module MiniKraken
117
118
  # (display (run* q (== q q))) ;; => (_0)
118
119
  # Reasoned S2, frame 1:20
119
120
  result = instance.run
120
- expect(ref_q.fresh?(instance.env)).to be_truthy
121
121
  expect(result.car).to eq(any_value(0))
122
122
  end
123
123
 
@@ -129,8 +129,6 @@ module MiniKraken
129
129
  # Reasoned S2, frame 1:21..23
130
130
  # (run* q (fresh (x) (== 'pea q))) ;; => (pea)
131
131
  result = instance.run
132
- expect(ref_q.fresh?(instance.env)).to be_falsey
133
- expect(ref_x.fresh?(fresh_env)).to be_truthy
134
132
 
135
133
  # Reasoned S2, frame 1:40
136
134
  expect(ref_q.different_from?(ref_x, fresh_env)).to be_truthy
@@ -145,8 +143,6 @@ module MiniKraken
145
143
  # Reasoned S2, frame 1:24
146
144
  # (run* q (fresh (x) (== 'pea x))) ;; => (_0)
147
145
  result = instance.run
148
- expect(ref_q.fresh?(instance.env)).to be_truthy
149
- expect(ref_x.fresh?(fresh_env)).to be_falsey
150
146
  expect(result.car).to eq(any_value(0))
151
147
  end
152
148
 
@@ -158,8 +154,6 @@ module MiniKraken
158
154
  # Reasoned S2, frame 1:25
159
155
  # (run* q (fresh (x) (== (cons x '()) q))) ;; => ((_0))
160
156
  result = instance.run
161
- expect(ref_q.fresh?(instance.env)).to be_truthy
162
- expect(ref_x.fresh?(fresh_env)).to be_truthy
163
157
  expect(result.car).to eq(cons(any_value(0)))
164
158
  end
165
159
 
@@ -190,7 +184,6 @@ module MiniKraken
190
184
  # Reasoned S2, frame 1:32
191
185
  # (run* q (== '(((pea)) pod) '(((pea)) pod))) ;; => (_0)
192
186
  result = instance.run
193
- expect(ref_q.fresh?(instance.env)).to be_truthy
194
187
  expect(result.car).to eq(any_value(0))
195
188
  end
196
189
 
@@ -204,7 +197,6 @@ module MiniKraken
204
197
  # Reasoned S2, frame 1:33
205
198
  # (run* q (== '(((pea)) pod) `(((pea)) ,q))) ;; => ('pod)
206
199
  result = instance.run
207
- expect(ref_q.fresh?(instance.env)).to be_falsey
208
200
  expect(result.car).to eq(pod)
209
201
  end
210
202
 
@@ -217,11 +209,10 @@ module MiniKraken
217
209
  # Reasoned S2, frame 1:34
218
210
  # (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pod)
219
211
  result = instance.run
220
- expect(ref_q.fresh?(instance.env)).to be_falsey
221
212
  expect(result.car).to eq(pea)
222
213
  end
223
214
 
224
- it 'should unify complex equality expressions (II)' do
215
+ it 'should unify complex equality expressions (III)' do
225
216
  expr1 = cons(cons(cons(ref_q)), pod)
226
217
  expr2 = cons(cons(cons(ref_x)), pod)
227
218
  goal = equals_goal(expr1, expr2)
@@ -231,12 +222,10 @@ module MiniKraken
231
222
  # Reasoned S2, frame 1:35
232
223
  # (run* q (fresh (x) (== '(((,q)) pod) `(((,x)) pod)))) ;; => (_0)
233
224
  result = instance.run
234
- expect(ref_q.fresh?(instance.env)).to be_truthy
235
- expect(ref_x.fresh?(fresh_env)).to be_truthy
236
225
  expect(result.car).to eq(any_value(0))
237
226
  end
238
227
 
239
- it 'should unify complex equality expressions (II)' do
228
+ it 'should unify complex equality expressions (IV)' do
240
229
  # Reasoned S2, frame 1:36
241
230
  # (run* q (fresh (x) (== '(((,q)) (,x)) `(((,x)) pod)))) ;; => ('pod)
242
231
  expr1 = cons(cons(cons(ref_q)), ref_x)
@@ -246,11 +235,6 @@ module MiniKraken
246
235
  instance = RunStarExpression.new('q', fresh_env)
247
236
 
248
237
  result = instance.run
249
-
250
- # Does propagate work correctly?
251
- expect(ref_q.fresh?(instance.env)).to be_truthy # x isn't defined here
252
- expect(ref_q.fresh?(fresh_env)).to be_falsey
253
- expect(ref_x.fresh?(fresh_env)).to be_falsey
254
238
  expect(result.car).to eq(pod)
255
239
  end
256
240
 
@@ -263,9 +247,6 @@ module MiniKraken
263
247
  instance = RunStarExpression.new('q', fresh_env)
264
248
 
265
249
  result = instance.run
266
- expect(ref_q.fresh?(instance.env)).to be_truthy # x isn't defined here
267
- expect(ref_q.fresh?(fresh_env)).to be_truthy
268
- expect(ref_x.fresh?(fresh_env)).to be_truthy
269
250
  expect(result.car).to eq(cons(any_value(0), cons(any_value(0))))
270
251
  end
271
252
 
@@ -280,17 +261,16 @@ module MiniKraken
280
261
  instance = RunStarExpression.new('q', fresh_env_x)
281
262
 
282
263
  result = instance.run
283
- expect(ref_q.fresh?(fresh_env_y)).to be_truthy
284
- expect(ref_q.bound?(fresh_env_y)).to be_truthy
285
- expect(ref_x.fresh?(fresh_env_y)).to be_truthy
286
- expect(ref_x.bound?(fresh_env_y)).to be_truthy
287
- expect(ref_y.fresh?(fresh_env_y)).to be_truthy
288
- expect(ref_y.bound?(fresh_env_y)).to be_truthy
289
264
 
290
265
  # y should be fused with x...
266
+ var_x = fresh_env_y.name2var('x')
267
+ var_y = fresh_env_y.name2var('y')
268
+ expect(var_x.i_name).to eq(var_y.i_name)
291
269
  expect(ref_y.fused_with?(ref_x, fresh_env_y)).to be_truthy
292
270
  expect(ref_x.names_fused(fresh_env_y)).to eq(['y'])
293
271
  expect(ref_y.names_fused(fresh_env_y)).to eq(['x'])
272
+
273
+ # q should be bound to '(,x ,x)
294
274
  expect(result.car).to eq(cons(any_value(0), cons(any_value(0))))
295
275
  end
296
276
 
@@ -304,16 +284,10 @@ module MiniKraken
304
284
  instance = RunStarExpression.new('q', fresh_env_x)
305
285
 
306
286
  result = instance.run
307
- expect(ref_q.fresh?(fresh_env_y)).to be_truthy
308
287
  # q should be bound to '(,x ,y)
309
- expect(ref_q.bound?(fresh_env_y)).to be_truthy
310
- expect(ref_x.fresh?(fresh_env_y)).to be_truthy
311
- expect(ref_x.bound?(fresh_env_y)).to be_falsey
312
- expect(ref_y.fresh?(fresh_env_y)).to be_truthy
313
- expect(ref_y.bound?(fresh_env_y)).to be_falsey
314
288
  expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
315
289
  end
316
-
290
+
317
291
  it 'should work with variable names' do
318
292
  # Reasoned S2, frame 1:42
319
293
  # (run* s (fresh (t) (fresh (u) (== '( ,t ,u) s)))) ;; => (_0 _1)
@@ -324,15 +298,9 @@ module MiniKraken
324
298
  instance = RunStarExpression.new('s', fresh_env_t)
325
299
 
326
300
  result = instance.run
327
- expect(ref_s.fresh?(fresh_env_u)).to be_truthy
328
301
  # s should be bound to '(,t ,u)
329
- expect(ref_s.bound?(fresh_env_u)).to be_truthy
330
- expect(ref_t.fresh?(fresh_env_u)).to be_truthy
331
- expect(ref_t.bound?(fresh_env_u)).to be_falsey
332
- expect(ref_u.fresh?(fresh_env_u)).to be_truthy
333
- expect(ref_u.bound?(fresh_env_u)).to be_falsey
334
302
  expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
335
- end
303
+ end
336
304
 
337
305
  it 'should support repeated variables' do
338
306
  # Reasoned S2, frame 1:43
@@ -344,13 +312,198 @@ module MiniKraken
344
312
  instance = RunStarExpression.new('q', fresh_env_x)
345
313
 
346
314
  result = instance.run
347
- expect(ref_q.fresh?(fresh_env_y)).to be_truthy
348
315
  # q should be bound to '(,x ,y, ,x)
349
- expect(ref_q.bound?(fresh_env_y)).to be_truthy
350
- expect(ref_x.fresh?(fresh_env_y)).to be_truthy
351
- expect(ref_y.fresh?(fresh_env_y)).to be_truthy
352
316
  expect(result.car).to eq(cons(any_value(0), cons(any_value(1), cons(any_value(0)))))
353
- end
317
+ end
318
+
319
+ it 'should support conjunction of two succeed' do
320
+ goal = conj2_goal(succeeds, succeeds)
321
+ instance = RunStarExpression.new('q', goal)
322
+
323
+ # Reasoned S2, frame 1:50
324
+ # (run* q (conj2 succeed succeed)) ;; => (_0)
325
+ result = instance.run
326
+ expect(result.car).to eq(any_value(0))
327
+ end
328
+
329
+ # TODO: fix erratic RSpec failure
330
+ it 'should support conjunction of one succeed and a successful goal' do
331
+ subgoal = equals_goal(corn, ref_q)
332
+ goal = conj2_goal(succeeds, subgoal)
333
+ instance = RunStarExpression.new('q', goal)
334
+
335
+ # Reasoned S2, frame 1:51
336
+ # (run* q (conj2 succeed (== 'corn q)) ;; => ('corn)
337
+ result = instance.run
338
+ expect(result.car).to eq(corn)
339
+ end
340
+
341
+ it 'should support conjunction of one fail and a successful goal' do
342
+ subgoal = equals_goal(corn, ref_q)
343
+ goal = conj2_goal(fails, subgoal)
344
+ instance = RunStarExpression.new('q', goal)
345
+
346
+ # Reasoned S2, frame 1:52
347
+ # (run* q (conj2 fail (== 'corn q)) ;; => ()
348
+ expect(instance.run).to be_null
349
+ end
350
+
351
+ it 'should support conjunction of two contradictory goals' do
352
+ subgoal1 = equals_goal(corn, ref_q)
353
+ subgoal2 = equals_goal(meal, ref_q)
354
+ goal = conj2_goal(subgoal1, subgoal2)
355
+ instance = RunStarExpression.new('q', goal)
356
+
357
+ # Reasoned S2, frame 1:53
358
+ # (run* q (conj2 (== 'corn q)(== 'meal q)) ;; => ()
359
+ expect(instance.run).to be_null
360
+ end
361
+
362
+ it 'should succeed the conjunction of two identical goals' do
363
+ subgoal1 = equals_goal(corn, ref_q)
364
+ subgoal2 = equals_goal(corn, ref_q)
365
+ goal = conj2_goal(subgoal1, subgoal2)
366
+ instance = RunStarExpression.new('q', goal)
367
+
368
+ # Reasoned S2, frame 1:54
369
+ # (run* q (conj2 (== 'corn q)(== 'corn q)) ;; => ('corn)
370
+ result = instance.run
371
+ expect(result.car).to eq(corn)
372
+ end
373
+
374
+ it 'should not yield solution when both disjunction arguments fail' do
375
+ goal = disj2_goal(fails, fails)
376
+ instance = RunStarExpression.new('q', goal)
377
+
378
+ # Reasoned S2, frame 1:55
379
+ # (run* q (disj2 fail fail)) ;; => ()
380
+ expect(instance.run).to be_null
381
+ end
382
+
383
+ it 'should yield solution when first argument succeed' do
384
+ subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
385
+ goal = disj2_goal(subgoal, fails)
386
+ instance = RunStarExpression.new('q', goal)
387
+
388
+ # Reasoned S2, frame 1:56
389
+ # (run* q (disj2 (equals 'olive q) fail)) ;; => ('olive)
390
+ result = instance.run
391
+ expect(result.car).to eq(olive)
392
+ end
393
+
394
+ it 'should yield solution when second argument succeed' do
395
+ subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
396
+ goal = disj2_goal(fails, subgoal)
397
+ instance = RunStarExpression.new('q', goal)
398
+
399
+ # Reasoned S2, frame 1:57
400
+ # (run* q (disj2 fail (equals 'oil q)) ;; => (oil)
401
+ result = instance.run
402
+ expect(result.car).to eq(oil)
403
+ end
404
+
405
+ it 'should yield solutions when both arguments succeed' do
406
+ subgoal1 = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
407
+ subgoal2 = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
408
+ goal = disj2_goal(subgoal1, subgoal2)
409
+ instance = RunStarExpression.new('q', goal)
410
+
411
+ # Reasoned S2, frame 1:58
412
+ # (run* q (disj2 (equals 'olive q) (equals 'oil q)) ;; => (olive oil)
413
+ result = instance.run
414
+ expect(result.car).to eq(olive)
415
+ expect(result.cdr.car).to eq(oil)
416
+ end
417
+
418
+ it 'should support the nesting of variables and disjunction' do
419
+ # Reasoned S2, frame 1:59
420
+ # (run* q (fresh (x) (fresh (y) (disj2 (== '( ,x ,y ) q) (== '( ,x ,y ) q)))))
421
+ # ;; => ((_0 _1) (_0 _1))
422
+ expr1 = cons(ref_x, cons(ref_y))
423
+ subgoal1 = equals_goal(expr1, ref_q)
424
+ expr2 = cons(ref_y, cons(ref_x))
425
+ subgoal2 = equals_goal(expr2, ref_q)
426
+ goal = disj2_goal(subgoal1, subgoal2)
427
+ fresh_env_y = FreshEnv.new(['y'], goal)
428
+ fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
429
+ instance = RunStarExpression.new('q', fresh_env_x)
430
+
431
+ result = instance.run
432
+ # q should be bound to '(,x ,y), then to '(,y ,x)
433
+ expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
434
+ expect(result.cdr.car).to eq(cons(any_value(0), cons(any_value(1))))
435
+ end
436
+
437
+ it 'should accept nesting of disj2 and conj2 (I)' do
438
+ conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
439
+ conjunction = conj2_goal(conj_subgoal, fails)
440
+ subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
441
+ goal = disj2_goal(conjunction, subgoal)
442
+ instance = RunStarExpression.new('x', goal)
443
+
444
+ # Reasoned S2, frame 1:62
445
+ # (run* x (disj2
446
+ # (conj2 (== 'olive x) fail)
447
+ # ('oil x))) ;; => (oil)
448
+ result = instance.run
449
+ expect(result.car).to eq(oil)
450
+ end
451
+
452
+ it 'should accept nesting of disj2 and conj2 (II)' do
453
+ conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
454
+ conjunction = conj2_goal(conj_subgoal, succeeds)
455
+ subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
456
+ goal = disj2_goal(conjunction, subgoal)
457
+ instance = RunStarExpression.new('x', goal)
458
+
459
+ # Reasoned S2, frame 1:63
460
+ # (run* x (disj2
461
+ # (conj2 (== 'olive x) succeed)
462
+ # ('oil x))) ;; => (olive oil)
463
+ result = instance.run
464
+ expect(result.car).to eq(olive)
465
+ expect(result.cdr.car).to eq(oil)
466
+ end
467
+
468
+ it 'should accept nesting of disj2 and conj2 (III)' do
469
+ conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
470
+ conjunction = conj2_goal(conj_subgoal, succeeds)
471
+ subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
472
+ goal = disj2_goal(subgoal, conjunction)
473
+ instance = RunStarExpression.new('x', goal)
474
+
475
+ # Reasoned S2, frame 1:64
476
+ # (run* x (disj2
477
+ # ('oil x)
478
+ # (conj2 (== 'olive x) succeed))) ;; => (oil olive)
479
+ result = instance.run
480
+ expect(result.car).to eq(oil)
481
+ expect(result.cdr.car).to eq(olive)
482
+ end
483
+
484
+ it 'should accept nesting of disj2 and conj2 (IV)' do
485
+ oil_goal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
486
+ disja = disj2_goal(succeeds, oil_goal)
487
+ olive_goal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
488
+ disjb = disj2_goal(olive_goal, disja)
489
+ virgin_goal = Core::Goal.new(Core::Equals.instance, [virgin, ref_x])
490
+ conjunction = conj2_goal(virgin_goal, fails)
491
+ goal = disj2_goal(conjunction, disjb)
492
+ instance = RunStarExpression.new('x', goal)
493
+
494
+ # Reasoned S2, frame 1:65
495
+ # (run* x (disj2
496
+ # (conj2(== 'virgin x) fails)
497
+ # (disj2
498
+ # (== 'olive x)
499
+ # (dis2
500
+ # succeeds
501
+ # (== 'oil x))))) ;; => (olive _0 oil)
502
+ result = instance.run
503
+ expect(result.car).to eq(olive)
504
+ expect(result.cdr.car).to eq(any_value(0))
505
+ expect(result.cdr.cdr.car).to eq(oil)
506
+ end
354
507
  end # context
355
508
  end # describe
356
509
  end # module
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/mini_kraken/version/'
4
+
1
5
  RSpec.describe MiniKraken do
2
6
  it 'has a version number' do
3
7
  expect(MiniKraken::VERSION).not_to be nil