mini_kraken 0.1.08 → 0.1.13

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.
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/disj2'
5
+ require_relative '../../lib/mini_kraken/core/equals'
6
+ require_relative '../../lib/mini_kraken/core/formal_arg'
7
+ require_relative '../../lib/mini_kraken/core/formal_ref'
8
+ require_relative '../../lib/mini_kraken/core/goal'
9
+ require_relative '../../lib/mini_kraken/core/goal_template'
10
+ require_relative '../../lib/mini_kraken/core/k_symbol'
11
+ require_relative '../../lib/mini_kraken/core/variable_ref'
12
+ require_relative '../../lib/mini_kraken/core/environment'
13
+
14
+ # Load the class under test
15
+ require_relative '../../lib/mini_kraken/core/def_relation'
16
+
17
+ module MiniKraken
18
+ module Core
19
+ describe DefRelation do
20
+ let(:tea) { KSymbol.new(:tea) }
21
+ let(:formal_t) { FormalArg.new('t') }
22
+ let(:t_ref) { FormalRef.new('t') }
23
+ let(:equals_tea) { GoalTemplate.new(Equals.instance, [tea, t_ref]) }
24
+ subject { DefRelation.new('teao', equals_tea, [formal_t]) }
25
+
26
+ context 'Initialization:' do
27
+ it 'should be initialized with a name, a goal template, formal args' do
28
+ expect { DefRelation.new('teao', equals_tea, [formal_t]) }.not_to raise_error
29
+ end
30
+
31
+ it 'should know its name' do
32
+ expect(subject.name).to eq('teao')
33
+ end
34
+
35
+ it 'should know its goal template' do
36
+ expect(subject.goal_template).to eq(equals_tea)
37
+ end
38
+
39
+ it 'should know its formals' do
40
+ expect(subject.formals).to eq([formal_t])
41
+ end
42
+ end # context
43
+
44
+ context 'Provided services:' do
45
+ let(:cup) { KSymbol.new(:cup) }
46
+ let(:ref_x) { VariableRef.new('x') }
47
+ let(:equals_cup) { GoalTemplate.new(Equals.instance, [cup, t_ref]) }
48
+ let(:g_template) { GoalTemplate.new(Disj2.instance, [equals_tea, equals_cup]) }
49
+ subject { DefRelation.new('teacup', g_template, [formal_t]) }
50
+ let(:env) { Environment.new }
51
+
52
+ it 'should provide solver for a single-node goal without var ref' do
53
+ defrel = DefRelation.new('teao', equals_tea, [formal_t])
54
+ solver = defrel.solver_for([tea], env)
55
+ outcome = solver.resume
56
+ expect(outcome).to be_successful
57
+ outcome = solver.resume
58
+ expect(outcome).to be_nil
59
+
60
+ solver = defrel.solver_for([cup], env)
61
+ outcome = solver.resume
62
+ expect(outcome).not_to be_successful
63
+ outcome = solver.resume
64
+ expect(outcome).to be_nil
65
+ end
66
+
67
+ it 'should provide solver for a single-node goal' do
68
+ defrel = DefRelation.new('teao', equals_tea, [formal_t])
69
+ env.add_var(Variable.new('x'))
70
+ solver = defrel.solver_for([ref_x], env)
71
+ outcome = solver.resume
72
+ expect(outcome).to be_successful
73
+ expect(ref_x.value(outcome)).to eq(tea)
74
+
75
+ outcome = solver.resume
76
+ expect(outcome).to be_nil
77
+ end
78
+
79
+ it 'should provide solver for a single-node goal' do
80
+ env.add_var(Variable.new('x'))
81
+ solver = subject.solver_for([ref_x], env)
82
+ outcome = solver.resume
83
+ expect(outcome).to be_successful
84
+ expect(ref_x.value(outcome)).to eq(tea)
85
+
86
+ outcome = solver.resume
87
+ expect(outcome).to be_successful
88
+ expect(ref_x.value(outcome)).to eq(cup)
89
+
90
+ outcome = solver.resume
91
+ expect(outcome).to be_nil
92
+ end
93
+ end # context
94
+ end # describe
95
+ end # module
96
+ end # module
@@ -275,9 +275,9 @@ module MiniKraken
275
275
 
276
276
  it 'should unify composite terms with variables' do
277
277
  # Reasoned S2, frame 1:36
278
- # (run* q (fresh (x) (== '(((,q)) (,x)) `(((,x)) pod)))) ;; => ('pod)
279
- expr1 = cons(cons(ref_q), ref_x)
280
- expr2 = cons(cons(ref_x), pod)
278
+ # (run* q (fresh (x) (== '(((,q)) ,x) `(((,x)) pod)))) ;; => ('pod)
279
+ expr1 = cons(cons(cons(ref_q)), ref_x)
280
+ expr2 = cons(cons(cons(ref_x)), pod)
281
281
 
282
282
  result = solve_for(expr1, expr2)
283
283
  # require 'debug'
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/disj2'
5
+ require_relative '../../lib/mini_kraken/core/equals'
6
+ require_relative '../../lib/mini_kraken/core/formal_arg'
7
+ require_relative '../../lib/mini_kraken/core/formal_ref'
8
+ require_relative '../../lib/mini_kraken/core/goal'
9
+ require_relative '../../lib/mini_kraken/core/k_symbol'
10
+ require_relative '../../lib/mini_kraken/core/variable_ref'
11
+ # require_relative '../../lib/mini_kraken/core/environment'
12
+
13
+ # Load the class under test
14
+ require_relative '../../lib/mini_kraken/core/goal_template'
15
+
16
+
17
+ module MiniKraken
18
+ module Core
19
+ describe GoalTemplate do
20
+ let(:tea) { KSymbol.new(:tea) }
21
+ let(:t_ref) { FormalRef.new('t') }
22
+ subject { GoalTemplate.new(Equals.instance, [tea, t_ref]) }
23
+
24
+ context 'Initialization:' do
25
+ it 'should be initialized with a relation and args' do
26
+ expect { GoalTemplate.new(Equals.instance, [tea, t_ref]) }.not_to raise_error
27
+ end
28
+
29
+ it 'should know its relation' do
30
+ expect(subject.relation).to eq(Equals.instance)
31
+ end
32
+
33
+ it 'should know its arguments' do
34
+ expect(subject.args[0]).to eq(tea)
35
+ expect(subject.args[1]).to eq(t_ref)
36
+ end
37
+ end # context
38
+
39
+ context 'Provided services:' do
40
+ let(:formal_t) { FormalArg.new('t') }
41
+ let(:cup) { KSymbol.new(:cup) }
42
+ let(:ref_x) { VariableRef.new('x') }
43
+ # let(:env) { Environment.new }
44
+
45
+ it 'should instantiate a single-node goal' do
46
+ expect(subject.instantiate([formal_t], [cup])).to be_kind_of(Goal)
47
+ goal = subject.instantiate([formal_t], [cup])
48
+ expect(goal.relation).to eq(Equals.instance)
49
+ expect(goal.actuals[0]).to eq(tea)
50
+ expect(goal.actuals[1]).to eq(cup)
51
+ end
52
+
53
+ it 'should instantiate a multiple-nodes goal' do
54
+ sub_tmp1 = GoalTemplate.new(Equals.instance, [tea, t_ref])
55
+ sub_tmp2 = GoalTemplate.new(Equals.instance, [cup, t_ref])
56
+ template = GoalTemplate.new(Disj2.instance, [sub_tmp1, sub_tmp2])
57
+
58
+ goal = template.instantiate([formal_t], [ref_x])
59
+ expect(goal.relation).to eq(Disj2.instance)
60
+ subgoal1 = goal.actuals[0]
61
+ expect(subgoal1).to be_kind_of(Goal)
62
+ expect(subgoal1.relation).to eq(Equals.instance)
63
+ expect(subgoal1.actuals[0]).to eq(tea)
64
+ expect(subgoal1.actuals[1]).to eq(ref_x)
65
+ subgoal2 = goal.actuals[1]
66
+ expect(subgoal2).to be_kind_of(Goal)
67
+ expect(subgoal2.relation).to eq(Equals.instance)
68
+ expect(subgoal2.actuals[0]).to eq(cup)
69
+ expect(subgoal2.actuals[1]).to eq(ref_x)
70
+ end
71
+ end # context
72
+ end # describe
73
+ end # module
74
+ end # module
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require 'ostruct'
5
+
6
+ # Load the class under test
7
+ require_relative '../../lib/mini_kraken/core/k_boolean'
8
+
9
+ module MiniKraken
10
+ module Core
11
+ describe KBoolean do
12
+ subject { KBoolean.new('#t') }
13
+
14
+ context 'Initialization:' do
15
+ it 'could be created with a Ruby true/false value' do
16
+ expect { KBoolean.new(true) }.not_to raise_error
17
+ expect { KBoolean.new(false) }.not_to raise_error
18
+ end
19
+
20
+ it 'could be created with a Ruby Symbol value' do
21
+ expect { KBoolean.new(:"#t") }.not_to raise_error
22
+ expect { KBoolean.new(:"#f") }.not_to raise_error
23
+ end
24
+
25
+ it 'could be created with a Ruby String value' do
26
+ expect { KBoolean.new('#t') }.not_to raise_error
27
+ expect { KBoolean.new('#f') }.not_to raise_error
28
+ end
29
+
30
+ it 'should know its value' do
31
+ expect(subject.value).to eq(true)
32
+ end
33
+
34
+ it 'should know that it is a ground term' do
35
+ env = double('mock-env')
36
+ expect(subject.ground?(env)).to be_truthy
37
+ end
38
+ end # context
39
+
40
+ context 'Provided services:' do
41
+ it 'should know whether it is equal to another instance' do
42
+ # Same type, same value
43
+ other = KBoolean.new(true)
44
+ expect(subject).to be_eql(other)
45
+
46
+ other = KBoolean.new(:"#t")
47
+ expect(subject).to be_eql(other)
48
+
49
+ other = KBoolean.new('#t')
50
+ expect(subject).to be_eql(other)
51
+
52
+ # Same type, other value
53
+ another = KBoolean.new(false)
54
+ expect(subject).not_to be_eql(another)
55
+
56
+ # Same type, other value
57
+ another = KBoolean.new(:"#f")
58
+ expect(subject).not_to be_eql(another)
59
+
60
+ # Same type, other value
61
+ another = KBoolean.new('#f')
62
+ expect(subject).not_to be_eql(another)
63
+
64
+ # Different type, same value
65
+ yet_another = OpenStruct.new(value: true)
66
+ expect(subject).not_to be_eql(yet_another)
67
+ end
68
+
69
+ it 'should know whether it has same value than other object' do
70
+ # Same type, same value
71
+ other = KBoolean.new(true)
72
+ expect(subject == other).to be_truthy
73
+
74
+ other = KBoolean.new(:"#t")
75
+ expect(subject == other).to be_truthy
76
+
77
+ other = KBoolean.new('#t')
78
+ expect(subject == other).to be_truthy
79
+
80
+ # Same type, other value
81
+ another = KBoolean.new(false)
82
+ expect(subject == another).to be_falsy
83
+
84
+ another = KBoolean.new(:"#f")
85
+ expect(subject == another).to be_falsy
86
+
87
+ another = KBoolean.new('#f')
88
+ expect(subject == another).to be_falsy
89
+
90
+ # Same duck type, same value
91
+ yet_another = OpenStruct.new(value: true)
92
+ expect(subject == yet_another).to be_truthy
93
+
94
+ # Different duck type, different value
95
+ still_another = OpenStruct.new(value: false)
96
+ expect(subject == still_another).to be_falsy
97
+
98
+ # Default Ruby representation, same value
99
+ expect(subject == true).to be_truthy
100
+
101
+ # Default Ruby representation, different value
102
+ expect(subject == false).to be_falsy
103
+ end
104
+ end # context
105
+ end # describe
106
+ end # module
107
+ end # module
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/vocabulary'
5
+
6
+ # Load the class under test
7
+ require_relative '../../lib/mini_kraken/core/outcome'
8
+
9
+ module MiniKraken
10
+ module Core
11
+ describe Outcome do
12
+ let(:voc) do
13
+ obj = Object.new
14
+ obj.extend(Vocabulary)
15
+ obj
16
+ end
17
+ subject { Outcome.new(:"#s", voc) }
18
+
19
+ context 'Initialization:' do
20
+ it 'should be created with a symbol and a vocabulary' do
21
+ expect { Outcome.new(:"#s", voc) }.not_to raise_error
22
+ end
23
+
24
+ it 'should know its resultant' do
25
+ expect(subject.resultant).to eq(:"#s")
26
+ end
27
+
28
+ it 'should know its parent' do
29
+ expect(subject.parent).to eq(voc)
30
+ end
31
+ end # context
32
+
33
+ context 'Provided services:' do
34
+ it 'should have a factory for failing outcome' do
35
+ instance = Outcome.failure(voc)
36
+ expect(instance.resultant).to eq(:"#u")
37
+ expect(instance.parent).to eq(voc)
38
+ end
39
+
40
+ it 'should have a factory for succeeding outcome' do
41
+ instance = Outcome.success(voc)
42
+ expect(instance.resultant).to eq(:"#s")
43
+ expect(instance.parent).to eq(voc)
44
+ end
45
+ end # context
46
+ end # describe
47
+ end # module
48
+ end # module
@@ -207,6 +207,12 @@ module MiniKraken
207
207
  expect(subject.get_rank('z')).to eq(0)
208
208
  expect(subject.get_rank('a')).to eq(1)
209
209
  end
210
+
211
+ it 'should provide a String representation of itself' do
212
+ expectation = +"#<#{subject.class}:#{subject.object_id.to_s(16)} @parent="
213
+ expectation << "#<#{subject.parent.class}:#{subject.parent.object_id.to_s(16)}>>"
214
+ expect(subject.inspect).to eq(expectation)
215
+ end
210
216
  end # context
211
217
  end # describe
212
218
  end # module
@@ -3,7 +3,9 @@
3
3
  require_relative '../spec_helper' # Use the RSpec framework
4
4
  require_relative '../../lib/mini_kraken/core/goal'
5
5
  require_relative '../../lib/mini_kraken/core/equals'
6
+ require_relative '../../lib/mini_kraken/core/fail'
6
7
  require_relative '../../lib/mini_kraken/core/k_symbol'
8
+ require_relative '../../lib/mini_kraken/core/succeed'
7
9
 
8
10
  # Load the class under test
9
11
  require_relative '../../lib/mini_kraken/glue/fresh_env'
@@ -17,15 +19,39 @@ module MiniKraken
17
19
  let(:sample_goal) do
18
20
  Core::Goal.new(Core::Equals.instance, [pea, pod])
19
21
  end
22
+ let(:pea_goal) do
23
+ Core::Goal.new(Core::Equals.instance, [pea, pea])
24
+ end
25
+ let(:goal_succeeds) { Core::Goal.new(Core::Succeed.instance, []) }
26
+ let(:goal_fails) { Core::Goal.new(Core::Fail.instance, []) }
20
27
  subject { FreshEnv.new(['q'], sample_goal) }
21
28
 
22
29
  context 'Initialization:' do
23
- it 'should be initialized with an array of names' do
30
+ it 'could be initialized with names and a goal' do
24
31
  expect { FreshEnv.new(['q'], sample_goal) }.not_to raise_error
25
32
  end
26
33
 
34
+ it 'could be initialized with names and goals' do
35
+ expect { FreshEnv.new(%w[x y], [pea_goal, goal_succeeds]) }.not_to raise_error
36
+ end
37
+
27
38
  it 'should know its variables' do
28
39
  expect(subject.vars['q']).not_to be_nil
40
+
41
+ instance = FreshEnv.new(%w[x y], sample_goal)
42
+ expect(instance.vars['x']).not_to be_nil
43
+ expect(instance.vars['y']).not_to be_nil
44
+ end
45
+
46
+ it 'should know its goal' do
47
+ # Single goal at initialization
48
+ expect(subject.goal).to eq(sample_goal)
49
+
50
+ # Multiple goals at initialization
51
+ instance = FreshEnv.new(['q'], [pea_goal, goal_succeeds])
52
+ expect(instance.goal.relation.name).to eq('conj2')
53
+ expect(instance.goal.actuals[0]).to eq(pea_goal)
54
+ expect(instance.goal.actuals[1]).to eq(goal_succeeds)
29
55
  end
30
56
  end # context
31
57
 
@@ -2,10 +2,15 @@
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/conde'
5
6
  require_relative '../../lib/mini_kraken/core/conj2'
7
+ require_relative '../../lib/mini_kraken/core/def_relation'
6
8
  require_relative '../../lib/mini_kraken/core/disj2'
7
9
  require_relative '../../lib/mini_kraken/core/equals'
8
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'
9
14
  require_relative '../../lib/mini_kraken/core/succeed'
10
15
 
11
16
  require_relative '../support/factory_methods'
@@ -21,16 +26,26 @@ module MiniKraken
21
26
  let(:pea) { k_symbol(:pea) }
22
27
  let(:pod) { k_symbol(:pod) }
23
28
  let(:sample_goal) { equals_goal(pea, pod) }
29
+ let(:fails) { Core::Goal.new(Core::Fail.instance, []) }
30
+ let(:succeeds) { Core::Goal.new(Core::Succeed.instance, []) }
24
31
  subject { RunStarExpression.new('q', sample_goal) }
25
32
 
26
33
  context 'Initialization:' do
27
- it 'should be initialized with a name and a goal' do
34
+ it 'could be initialized with a name and a goal' do
28
35
  expect { RunStarExpression.new('q', sample_goal) }.not_to raise_error
29
36
  end
30
37
 
38
+ it 'could be initialized with multiple names and a goal' do
39
+ expect { RunStarExpression.new(%w[r x y], sample_goal) }.not_to raise_error
40
+ end
41
+
42
+ it 'could be initialized with multiple names and goals' do
43
+ expect { RunStarExpression.new(%w[r x y], [succeeds, succeeds]) }.not_to raise_error
44
+ end
45
+
31
46
  it 'should know its variables' do
32
47
  expect(subject.env.vars['q']).not_to be_nil
33
- expect(subject.var.name).to eq('q')
48
+ expect(subject.env.vars.values[0].name).to eq('q')
34
49
  end
35
50
 
36
51
  it 'should know its goal' do
@@ -39,19 +54,40 @@ module MiniKraken
39
54
  end # context
40
55
 
41
56
  context 'Provided services:' do
57
+ let(:k_false) { k_boolean(false) }
58
+ let(:k_true) { k_boolean(true) }
59
+ let(:bean) { k_symbol(:bean) }
42
60
  let(:corn) { k_symbol(:corn) }
61
+ let(:cup) { k_symbol(:cup) }
62
+ let(:green) { k_symbol(:green) }
63
+ let(:lentil) { k_symbol(:lentil) }
43
64
  let(:meal) { k_symbol(:meal) }
44
65
  let(:oil) { k_symbol(:oil) }
45
66
  let(:olive) { k_symbol(:olive) }
67
+ let(:red) { k_symbol(:red) }
68
+ let(:soup) { k_symbol(:soup) }
69
+ let(:split) { k_symbol(:split) }
70
+ let(:tea) { k_symbol(:tea) }
46
71
  let(:virgin) { k_symbol(:virgin) }
47
72
  let(:ref_q) { Core::VariableRef.new('q') }
73
+ let(:ref_r) { Core::VariableRef.new('r') }
48
74
  let(:ref_x) { Core::VariableRef.new('x') }
49
75
  let(:ref_y) { Core::VariableRef.new('y') }
76
+ let(:ref_z) { Core::VariableRef.new('z') }
50
77
  let(:ref_s) { Core::VariableRef.new('s') }
51
78
  let(:ref_t) { Core::VariableRef.new('t') }
52
79
  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, []) }
80
+ let(:ref_z) { Core::VariableRef.new('z') }
81
+ let(:t_ref) { Core::FormalRef.new('t') }
82
+ let(:equals_tea) { Core::GoalTemplate.new(Core::Equals.instance, [tea, t_ref]) }
83
+ let(:equals_cup) { Core::GoalTemplate.new(Core::Equals.instance, [cup, t_ref]) }
84
+ let(:g_template) { Core::GoalTemplate.new(Core::Disj2.instance, [equals_tea, equals_cup]) }
85
+ let(:formal_t) { Core::FormalArg.new('t') }
86
+
87
+ # Reasoned S2, frame 1:82
88
+ # (defrel (teacupo t)
89
+ # (disj2 (== 'tea t) (== 'cup t)))
90
+ let(:teacupo_rel) { Core::DefRelation.new('teacupo', g_template, [formal_t]) }
55
91
 
56
92
  it 'should return a null list with the fail goal' do
57
93
  # Reasoned S2, frame 1:7
@@ -90,6 +126,7 @@ module MiniKraken
90
126
 
91
127
  it 'should return a null list with the succeed goal' do
92
128
  instance = RunStarExpression.new('q', succeeds)
129
+ expect(instance.env.vars).to be_include('q')
93
130
 
94
131
  # (display (run* q succeed)) ;; => (_0)
95
132
  # Reasoned S2, frame 1:16
@@ -386,7 +423,7 @@ module MiniKraken
386
423
  instance = RunStarExpression.new('q', goal)
387
424
 
388
425
  # Reasoned S2, frame 1:56
389
- # (run* q (disj2 (equals 'olive q) fail)) ;; => ('olive)
426
+ # (run* q (disj2 (== 'olive q) fail)) ;; => ('olive)
390
427
  result = instance.run
391
428
  expect(result.car).to eq(olive)
392
429
  end
@@ -397,7 +434,7 @@ module MiniKraken
397
434
  instance = RunStarExpression.new('q', goal)
398
435
 
399
436
  # Reasoned S2, frame 1:57
400
- # (run* q (disj2 fail (equals 'oil q)) ;; => (oil)
437
+ # (run* q (disj2 fail (== 'oil q))) ;; => (oil)
401
438
  result = instance.run
402
439
  expect(result.car).to eq(oil)
403
440
  end
@@ -409,7 +446,7 @@ module MiniKraken
409
446
  instance = RunStarExpression.new('q', goal)
410
447
 
411
448
  # Reasoned S2, frame 1:58
412
- # (run* q (disj2 (equals 'olive q) (equals 'oil q)) ;; => (olive oil)
449
+ # (run* q (disj2 (== 'olive q) (== 'oil q))) ;; => (olive oil)
413
450
  result = instance.run
414
451
  expect(result.car).to eq(olive)
415
452
  expect(result.cdr.car).to eq(oil)
@@ -504,6 +541,462 @@ module MiniKraken
504
541
  expect(result.cdr.car).to eq(any_value(0))
505
542
  expect(result.cdr.cdr.car).to eq(oil)
506
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 simplication 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
507
1000
  end # context
508
1001
  end # describe
509
1002
  end # module