mini_kraken 0.1.01 → 0.1.02

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/README.md +0 -3
  4. data/lib/mini_kraken/core/any_value.rb +29 -0
  5. data/lib/mini_kraken/core/association.rb +21 -0
  6. data/lib/mini_kraken/core/association_walker.rb +179 -0
  7. data/lib/mini_kraken/core/atomic_term.rb +64 -0
  8. data/lib/mini_kraken/core/binary_relation.rb +61 -0
  9. data/lib/mini_kraken/core/composite_term.rb +54 -0
  10. data/lib/mini_kraken/core/cons_cell.rb +44 -0
  11. data/lib/mini_kraken/core/duck_fiber.rb +44 -0
  12. data/lib/mini_kraken/core/environment.rb +59 -0
  13. data/lib/mini_kraken/core/equals.rb +216 -0
  14. data/lib/mini_kraken/core/fail.rb +8 -5
  15. data/lib/mini_kraken/core/freshness.rb +42 -0
  16. data/lib/mini_kraken/core/goal.rb +31 -6
  17. data/lib/mini_kraken/core/k_integer.rb +15 -0
  18. data/lib/mini_kraken/core/k_symbol.rb +15 -0
  19. data/lib/mini_kraken/core/nullary_relation.rb +11 -3
  20. data/lib/mini_kraken/core/outcome.rb +35 -0
  21. data/lib/mini_kraken/core/relation.rb +31 -4
  22. data/lib/mini_kraken/core/succeed.rb +13 -1
  23. data/lib/mini_kraken/core/term.rb +7 -0
  24. data/lib/mini_kraken/core/variable.rb +45 -3
  25. data/lib/mini_kraken/core/variable_ref.rb +76 -0
  26. data/lib/mini_kraken/core/vocabulary.rb +161 -0
  27. data/lib/mini_kraken/glue/fresh_env.rb +31 -0
  28. data/lib/mini_kraken/glue/run_star_expression.rb +43 -0
  29. data/lib/mini_kraken/version.rb +1 -1
  30. data/spec/core/association_spec.rb +38 -0
  31. data/spec/core/association_walker_spec.rb +191 -0
  32. data/spec/core/cons_cell_spec.rb +63 -0
  33. data/spec/core/duck_fiber_spec.rb +62 -0
  34. data/spec/core/environment_spec.rb +154 -0
  35. data/spec/core/equals_spec.rb +289 -0
  36. data/spec/core/fail_spec.rb +16 -0
  37. data/spec/core/goal_spec.rb +36 -10
  38. data/spec/core/k_symbol_spec.rb +72 -0
  39. data/spec/core/succeed_spec.rb +43 -0
  40. data/spec/core/variable_ref_spec.rb +31 -0
  41. data/spec/core/variable_spec.rb +11 -3
  42. data/spec/core/vocabulary_spec.rb +188 -0
  43. data/spec/glue/fresh_env_spec.rb +36 -0
  44. data/spec/glue/run_star_expression_spec.rb +247 -0
  45. data/spec/support/factory_methods.rb +54 -0
  46. metadata +46 -13
  47. data/lib/mini_kraken/core/facade.rb +0 -45
  48. data/lib/mini_kraken/core/formal_arg.rb +0 -6
  49. data/lib/mini_kraken/core/publisher.rb +0 -27
  50. data/lib/mini_kraken/core/run_star_expression.rb +0 -34
  51. data/lib/mini_kraken/dsl/kraken_dsl.rb +0 -12
  52. data/spec/core/facade_spec.rb +0 -38
  53. data/spec/core/run_star_expression_spec.rb +0 -43
  54. data/spec/dsl/kraken_dsl_spec.rb +0 -31
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+
5
+ # Load the class under test
6
+ require_relative '../../lib/mini_kraken/core/succeed'
7
+
8
+ module MiniKraken
9
+ module Core
10
+ describe Succeed do
11
+ subject { Succeed.instance }
12
+
13
+ context 'Initialization:' do
14
+ it 'should have one instance' do
15
+ expect { Succeed.instance }.not_to raise_error
16
+ end
17
+
18
+ it 'should know its name' do
19
+ expect(subject.name).to eq('succeed')
20
+ end
21
+ end # context
22
+
23
+ context 'Provided services:' do
24
+ it 'should unconditionally return a success result' do
25
+ args = double('fake-args')
26
+ env = double('fake-env')
27
+
28
+ solver = nil
29
+ expect { solver = subject.solver_for(args, env) }.not_to raise_error
30
+
31
+ # Solver should quack like a Fiber
32
+ dummy_arg = double('dummy-stuff')
33
+ result = solver.resume(dummy_arg)
34
+ expect(result).to eq(BasicSuccess)
35
+
36
+ # Only one "solution", next 'resume' call should return nil
37
+ result = solver.resume(dummy_arg)
38
+ expect(result).to be_nil
39
+ end
40
+ end # context
41
+ end # describe
42
+ end # module
43
+ end # module
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+
5
+ # Load the class under test
6
+ require_relative '../../lib/mini_kraken/core/variable_ref'
7
+
8
+ module MiniKraken
9
+ module Core
10
+ describe VariableRef do
11
+ subject { VariableRef.new('q') }
12
+
13
+ context 'Initialization:' do
14
+ it 'should be initialized with the name of variable' do
15
+ expect { VariableRef.new('q') }.not_to raise_error
16
+ end
17
+
18
+ it 'should know the name of a variable' do
19
+ expect(subject.var_name).to eq('q')
20
+ end
21
+
22
+ # it 'should be fresh by default' do
23
+ # expect(subject).to be_fresh
24
+ # end
25
+ end # context
26
+
27
+ context 'Provided services:' do
28
+ end # context
29
+ end # describe
30
+ end # module
31
+ end # module
@@ -1,27 +1,35 @@
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/environment'
4
5
 
5
6
  # Load the class under test
6
- require_relative '../../lib/mini_kraken/core/variable'
7
+ require_relative '../../lib/mini_kraken/core/variable'
8
+
7
9
 
8
10
  module MiniKraken
9
11
  module Core
10
12
  describe Variable do
13
+ let(:env) { Environment.new }
11
14
  subject { Variable.new('q') }
12
15
 
13
16
  context 'Initialization:' do
14
17
  it 'should be initialized with a name' do
15
18
  expect { Variable.new('q') }.not_to raise_error
16
19
  end
17
-
20
+
18
21
  it 'should know its name' do
19
22
  expect(subject.name).to eq('q')
20
23
  end
24
+
25
+ it 'should be fresh by default' do
26
+ env.add_var(subject)
27
+ expect(subject.fresh?(env)).to be_truthy
28
+ end
21
29
  end # context
22
30
 
23
31
  context 'Provided services:' do
24
32
  end # context
25
33
  end # describe
26
34
  end # module
27
- end # module
35
+ end # module
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/association'
5
+ require_relative '../../lib/mini_kraken/core/k_symbol'
6
+ require_relative '../../lib/mini_kraken/core/variable_ref'
7
+ require_relative '../support/factory_methods'
8
+
9
+ # Load the class under test
10
+ require_relative '../../lib/mini_kraken/core/vocabulary'
11
+
12
+
13
+ module MiniKraken
14
+ module Core
15
+
16
+ class TestVocabulary
17
+ include Vocabulary
18
+
19
+ def initialize(aParent = nil)
20
+ init_vocabulary(aParent)
21
+ end
22
+ end # class
23
+
24
+ module VariableBearer
25
+ attr_reader :vars
26
+
27
+ def init_var_bearer
28
+ @vars = {}
29
+ self
30
+ end
31
+
32
+ def add_var(aVarName)
33
+ vars[aVarName] = aVarName.hash # Just for testing purposes
34
+ end
35
+ end # module
36
+
37
+ describe Vocabulary do
38
+ include FactoryMethods
39
+
40
+ let(:parent) { TestVocabulary.new }
41
+ subject { TestVocabulary.new }
42
+
43
+ context 'Initialization:' do
44
+ it 'could be initialized without a parent' do
45
+ expect { TestVocabulary.new }.not_to raise_error
46
+ end
47
+
48
+ it 'could be initialized with a parent' do
49
+ expect { TestVocabulary.new(parent) }.not_to raise_error
50
+ end
51
+
52
+ it 'should know its parent (if any)' do
53
+ expect(subject.parent).to be_nil
54
+ instance = TestVocabulary.new(parent)
55
+ expect(instance.parent).to eq(parent)
56
+ end
57
+
58
+ it 'should have no associations at initialization' do
59
+ expect(subject.associations).to be_empty
60
+ end
61
+ end # context
62
+
63
+ context 'Provided services:' do
64
+ let(:pea) { KSymbol.new(:pea) }
65
+ let(:pod) { KSymbol.new(:pod) }
66
+ let(:ref_q) { VariableRef.new('q') }
67
+ let(:ref_x) { VariableRef.new('x') }
68
+ let(:grandma) do
69
+ voc = TestVocabulary.new
70
+ voc.extend(VariableBearer)
71
+ voc.init_var_bearer
72
+ end
73
+ let(:mother) { TestVocabulary.new(grandma) }
74
+ subject { TestVocabulary.new(mother) }
75
+
76
+ it 'should provide a walker over ancestors' do
77
+ walker = subject.ancestor_walker
78
+ expect(walker).to be_kind_of(Fiber)
79
+ expect(walker.resume).to eq(subject)
80
+ expect(walker.resume).to eq(mother)
81
+ expect(walker.resume).to eq(grandma)
82
+ expect(walker.resume).to be_nil
83
+ end
84
+
85
+ it 'should know if a variable is defined' do
86
+ expect(subject.include?('q')).to be_falsey
87
+ grandma.add_var('x')
88
+ expect(subject.include?('q')).to be_falsey
89
+ expect(grandma.include?('x')).to be_truthy
90
+ expect(mother.include?('x')).to be_truthy
91
+ expect(subject.include?('x')).to be_truthy
92
+ subject.extend(VariableBearer)
93
+ subject.init_var_bearer
94
+ subject.add_var('y')
95
+ expect(subject.include?('y')).to be_truthy
96
+ expect(mother.include?('y')).to be_falsey
97
+ end
98
+
99
+ it 'should allow the addition of associations' do
100
+ grandma.add_var('q')
101
+ expect(subject['q']).to be_empty
102
+ mother.add_assoc(Association.new('q', pea))
103
+ expect(subject['q'].size).to eq(1)
104
+ expect(subject['q'].first.value).to eq(pea)
105
+
106
+ subject.add_assoc(Association.new('q', ref_x))
107
+ expect(subject['q'].size).to eq(2)
108
+ expect(subject['q'].first.value).to eq(ref_x)
109
+ expect(subject['q'].last.value).to eq(pea)
110
+ end
111
+
112
+ it 'should allow the deletion of associations' do
113
+ grandma.add_var('q')
114
+ mother.add_assoc(Association.new('q', pea))
115
+ subject.add_assoc(Association.new('q', ref_x))
116
+ expect(mother.associations.size).to eq(1)
117
+ expect(subject.associations.size).to eq(1)
118
+
119
+ subject.clear
120
+ expect(subject.associations).to be_empty
121
+
122
+ mother.clear
123
+ expect(mother.associations).to be_empty
124
+ end
125
+
126
+ it 'should say fresh when a variable has no association at all' do
127
+ grandma.add_var('q')
128
+ grandma.add_var('x')
129
+ expect(subject.fresh?(ref_q)).to be_truthy
130
+ subject.add_assoc(Association.new('q', ref_x)) # Dependency: q --> x
131
+ expect(subject.fresh?(ref_x)).to be_truthy
132
+ end
133
+
134
+ it 'should say not fresh when variable --> atomic value' do
135
+ grandma.add_var('q')
136
+ grandma.add_var('x')
137
+ subject.add_assoc(Association.new('q', ref_x)) # Dependency: q --> x
138
+ expect(subject.fresh?(ref_q)).to be_truthy
139
+
140
+ # Associate with an atomic term
141
+ subject.add_assoc(Association.new('q', pea))
142
+ expect(subject.fresh?(ref_q)).to be_falsey
143
+ end
144
+
145
+ it 'should say not fresh when variable --> composite of atomics' do
146
+ grandma.add_var('q')
147
+
148
+ # Composite having only atomic terms as leaf elements
149
+ expr = cons(pea, cons(pod))
150
+ subject.add_assoc(Association.new('q', expr))
151
+ expect(subject.fresh?(ref_q)).to be_falsey
152
+ end
153
+
154
+ it 'say not fresh when variable --> composite of atomics & bound var' do
155
+ grandma.add_var('q')
156
+ grandma.add_var('x')
157
+ subject.add_assoc(Association.new('x', pea)) # Dependency: x --> pea
158
+ expr = cons(pea, cons(pod, cons(ref_x)))
159
+ subject.add_assoc(Association.new('q', expr))
160
+ expect(subject.fresh?(ref_q)).to be_falsey
161
+ end
162
+
163
+ it 'say not fresh when variable --> composite of atomics & fresh var' do
164
+ grandma.add_var('q')
165
+ grandma.add_var('x')
166
+ expr = cons(pea, cons(pod, cons(ref_x)))
167
+ subject.add_assoc(Association.new('q', expr))
168
+ expect(subject.fresh?(ref_q)).to be_truthy
169
+ end
170
+
171
+ it 'say not fresh when variables are fused & one is ground' do
172
+ grandma.add_var('q')
173
+ grandma.add_var('x')
174
+
175
+ # Beware of cyclic structure
176
+ subject.add_assoc(Association.new('q', ref_x)) # Dependency: q --> x
177
+ subject.add_assoc(Association.new('x', ref_q)) # Dependency: x --> q
178
+ expect(subject.fresh?(ref_x)).to be_truthy
179
+ expect(subject.fresh?(ref_q)).to be_truthy
180
+
181
+ # Associate with an atomic term
182
+ subject.add_assoc(Association.new('x', pea))
183
+ expect(subject.fresh?(ref_q)).to be_falsey
184
+ end
185
+ end # context
186
+ end # describe
187
+ end # module
188
+ end # module
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/goal'
5
+ require_relative '../../lib/mini_kraken/core/equals'
6
+ require_relative '../../lib/mini_kraken/core/k_symbol'
7
+
8
+ # Load the class under test
9
+ require_relative '../../lib/mini_kraken/glue/fresh_env'
10
+
11
+
12
+ module MiniKraken
13
+ module Glue
14
+ describe FreshEnv do
15
+ let(:pea) { Core::KSymbol.new(:pea) }
16
+ let(:pod) { Core::KSymbol.new(:pod) }
17
+ let(:sample_goal) do
18
+ Core::Goal.new(Core::Equals.instance, [pea, pod])
19
+ end
20
+ subject { FreshEnv.new(['q'], sample_goal) }
21
+
22
+ context 'Initialization:' do
23
+ it 'should be initialized with an array of names' do
24
+ expect { FreshEnv.new(['q'], sample_goal) }.not_to raise_error
25
+ end
26
+
27
+ it 'should know its variables' do
28
+ expect(subject.vars['q']).not_to be_nil
29
+ end
30
+ end # context
31
+
32
+ context 'Provided services:' do
33
+ end # context
34
+ end # describe
35
+ end # module
36
+ end # module
@@ -0,0 +1,247 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/goal'
5
+ require_relative '../../lib/mini_kraken/core/equals'
6
+ require_relative '../../lib/mini_kraken/core/fail'
7
+ require_relative '../../lib/mini_kraken/core/succeed'
8
+
9
+ require_relative '../support/factory_methods'
10
+
11
+ # Load the class under test
12
+ require_relative '../../lib/mini_kraken/glue/run_star_expression'
13
+
14
+
15
+ module MiniKraken
16
+ module Glue
17
+ describe RunStarExpression do
18
+ include FactoryMethods
19
+ let(:pea) { k_symbol(:pea) }
20
+ let(:pod) { k_symbol(:pod) }
21
+ let(:sample_goal) { equals_goal(pea, pod) }
22
+ subject { RunStarExpression.new('q', sample_goal) }
23
+
24
+ context 'Initialization:' do
25
+ it 'should be initialized with a name and a goal' do
26
+ expect { RunStarExpression.new('q', sample_goal) }.not_to raise_error
27
+ end
28
+
29
+ it 'should know its variables' do
30
+ expect(subject.env.vars['q']).not_to be_nil
31
+ expect(subject.var.name).to eq('q')
32
+ end
33
+
34
+ it 'should know its goal' do
35
+ expect(subject.env.goal).to eq(sample_goal)
36
+ end
37
+ end # context
38
+
39
+ context 'Provided services:' do
40
+ let(:ref_q) { Core::VariableRef.new('q') }
41
+ let(:ref_x) { Core::VariableRef.new('x') }
42
+
43
+ it "should return a null list with the fail goal" do
44
+ # Reasoned S2, frame 1:7
45
+ # (run* q #u) ;; => ()
46
+ failing = Core::Goal.new(Core::Fail.instance, [])
47
+ instance = RunStarExpression.new('q', failing)
48
+
49
+ expect(instance.run).to be_null
50
+ expect(ref_q.fresh?(instance.env)).to be_truthy
51
+ end
52
+
53
+ it "should return a null list when a goal fails" do
54
+ # Reasoned S2, frame 1:10
55
+ # (run* q (== 'pea 'pod) ;; => ()
56
+
57
+ expect(subject.run).to be_null
58
+ expect(ref_q.fresh?(subject.env)).to be_truthy
59
+ end
60
+
61
+ it 'should unify the variable with the equals goal with symbol' do
62
+ goal = equals_goal(ref_q, pea)
63
+ instance = RunStarExpression.new('q', goal)
64
+
65
+ # Reasoned S2, frame 1:11
66
+ # (run* q (== q 'pea) ;; => (pea)
67
+ expect(instance.run.car).to eq(pea)
68
+ expect(ref_q.fresh?(instance.env)).to be_falsey
69
+ end
70
+
71
+ it 'should unify the righthand variable(s)' do
72
+ goal = equals_goal(pea, ref_q)
73
+ instance = RunStarExpression.new('q', goal)
74
+
75
+ # Reasoned S2, frame 1:12
76
+ # (run* q (== 'pea q) ;; => (pea)
77
+ expect(instance.run.car).to eq(pea)
78
+
79
+ # Reasoned S2, frame 1:15
80
+ expect(ref_q.fresh?(instance.env)).to be_falsey
81
+ end
82
+
83
+ it 'should return a null list with the succeed goal' do
84
+ success = Core::Goal.new(Core::Succeed.instance, [])
85
+ instance = RunStarExpression.new('q', success)
86
+
87
+ # (display (run* q succeed)) ;; => (_0)
88
+ # Reasoned S2, frame 1:16
89
+ result = instance.run
90
+ expect(ref_q.fresh?(instance.env)).to be_truthy
91
+
92
+ # Reasoned S2, frame 1:17
93
+ expect(result.car).to eq(any_value(0))
94
+ end
95
+
96
+ it 'should keep variable fresh when no unification occurs (I)' do
97
+ goal = equals_goal(pea, pea)
98
+ instance = RunStarExpression.new('q', goal)
99
+
100
+ # (display (run* q (== 'pea 'pea))) ;; => (_0)
101
+ # Reasoned S2, frame 1:19
102
+ result = instance.run
103
+ expect(ref_q.fresh?(instance.env)).to be_truthy
104
+ expect(result.car).to eq(any_value(0))
105
+ end
106
+
107
+ it 'should keep variable fresh when no unification occurs (III)' do
108
+ ref1_q = Core::VariableRef.new('q')
109
+ ref2_q = Core::VariableRef.new('q')
110
+ goal = equals_goal(ref1_q, ref2_q)
111
+ instance = RunStarExpression.new('q', goal)
112
+
113
+ # (display (run* q (== q q))) ;; => (_0)
114
+ # Reasoned S2, frame 1:20
115
+ result = instance.run
116
+ expect(ref_q.fresh?(instance.env)).to be_truthy
117
+ expect(result.car).to eq(any_value(0))
118
+ end
119
+
120
+ it 'should accept the nesting of sub-environment' do
121
+ goal = equals_goal(pea, ref_q)
122
+ fresh_env = FreshEnv.new(['x'], goal)
123
+ instance = RunStarExpression.new('q', fresh_env)
124
+
125
+ # Reasoned S2, frame 1:21..23
126
+ # (run* q (fresh (x) (== 'pea q))) ;; => (pea)
127
+ result = instance.run
128
+ expect(ref_q.fresh?(instance.env)).to be_falsey
129
+ expect(ref_x.fresh?(fresh_env)).to be_truthy
130
+ expect(result.car).to eq(pea)
131
+ end
132
+
133
+ it 'should unify nested variables' do
134
+ goal = equals_goal(pea, ref_x)
135
+ fresh_env = FreshEnv.new(['x'], goal)
136
+ instance = RunStarExpression.new('q', fresh_env)
137
+
138
+ # Reasoned S2, frame 1:24
139
+ # (run* q (fresh (x) (== 'pea x))) ;; => (_0)
140
+ result = instance.run
141
+ expect(ref_q.fresh?(instance.env)).to be_truthy
142
+ expect(ref_x.fresh?(fresh_env)).to be_falsey
143
+ expect(result.car).to eq(any_value(0))
144
+ end
145
+
146
+ it 'should accept expression with variables' do
147
+ goal = equals_goal(cons(ref_x), ref_q)
148
+ fresh_env = FreshEnv.new(['x'], goal)
149
+ instance = RunStarExpression.new('q', fresh_env)
150
+
151
+ # Reasoned S2, frame 1:25
152
+ # (run* q (fresh (x) (== (cons x '()) q))) ;; => ((_0))
153
+ result = instance.run
154
+ expect(ref_q.fresh?(instance.env)).to be_truthy
155
+ expect(ref_x.fresh?(fresh_env)).to be_truthy
156
+ expect(result.car).to eq(cons(any_value(0)))
157
+ end
158
+
159
+ it 'should accept fused variables' do
160
+ goal = equals_goal(ref_x, ref_q)
161
+ fresh_env = FreshEnv.new(['x'], goal)
162
+ instance = RunStarExpression.new('q', fresh_env)
163
+
164
+ # Reasoned S2, frame 1:31
165
+ # (run* q (fresh (x) (== x q))) ;; => (_0)
166
+ result = instance.run
167
+ expect(ref_q.fresh?(instance.env)).to be_truthy
168
+ expect(ref_x.fresh?(fresh_env)).to be_truthy
169
+ expect(result.car).to eq(any_value(0))
170
+ end
171
+
172
+ it 'should cope with complex equality expressions' do
173
+ expr1 = cons(cons(cons(pea)), pod)
174
+ expr2 = cons(cons(cons(pea)), pod)
175
+ goal = equals_goal(expr1, expr2)
176
+ instance = RunStarExpression.new('q', goal)
177
+
178
+ # Reasoned S2, frame 1:32
179
+ # (run* q (== '(((pea)) pod) '(((pea)) pod))) ;; => (_0)
180
+ result = instance.run
181
+ expect(ref_q.fresh?(instance.env)).to be_truthy
182
+ expect(result.car).to eq(any_value(0))
183
+ end
184
+
185
+ it 'should unify complex equality expressions (I)' do
186
+ expr1 = cons(cons(cons(pea)), pod)
187
+ expr2 = cons(cons(cons(pea)), ref_q)
188
+ goal = equals_goal(expr1, expr2)
189
+ instance = RunStarExpression.new('q', goal)
190
+
191
+ # Beware: quasiquoting
192
+ # Reasoned S2, frame 1:33
193
+ # (run* q (== '(((pea)) pod) `(((pea)) ,q))) ;; => ('pod)
194
+ result = instance.run
195
+ expect(ref_q.fresh?(instance.env)).to be_falsey
196
+ expect(result.car).to eq(pod)
197
+ end
198
+
199
+ it 'should unify complex equality expressions (II)' do
200
+ expr1 = cons(cons(cons(ref_q)), pod)
201
+ expr2 = cons(cons(cons(pea)), pod)
202
+ goal = equals_goal(expr1, expr2)
203
+ instance = RunStarExpression.new('q', goal)
204
+
205
+ # Reasoned S2, frame 1:34
206
+ # (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pod)
207
+ result = instance.run
208
+ expect(ref_q.fresh?(instance.env)).to be_falsey
209
+ expect(result.car).to eq(pea)
210
+ end
211
+
212
+ it 'should unify complex equality expressions (II)' do
213
+ expr1 = cons(cons(cons(ref_q)), pod)
214
+ expr2 = cons(cons(cons(ref_x)), pod)
215
+ goal = equals_goal(expr1, expr2)
216
+ fresh_env = FreshEnv.new(['x'], goal)
217
+ instance = RunStarExpression.new('q', fresh_env)
218
+
219
+ # Reasoned S2, frame 1:35
220
+ # (run* q (fresh (x) (== '(((,q)) pod) `(((,x)) pod)))) ;; => (_0)
221
+ result = instance.run
222
+ expect(ref_q.fresh?(instance.env)).to be_truthy
223
+ expect(ref_x.fresh?(fresh_env)).to be_truthy
224
+ expect(result.car).to eq(any_value(0))
225
+ end
226
+
227
+ it 'should unify complex equality expressions (II)' do
228
+ # # Reasoned S2, frame 1:36
229
+ # # (run* q (fresh (x) (== '(((,q)) (,x)) `(((,x)) pod)))) ;; => ('pod)
230
+ expr1 = cons(cons(cons(ref_q)), ref_x)
231
+ expr2 = cons(cons(cons(ref_x)), pod)
232
+ goal = equals_goal(expr1, expr2)
233
+ fresh_env = FreshEnv.new(['x'], goal)
234
+ instance = RunStarExpression.new('q', fresh_env)
235
+
236
+ result = instance.run
237
+
238
+ # Does propagate work correctly?
239
+ expect(ref_q.fresh?(instance.env)).to be_truthy # x isn't defined here
240
+ expect(ref_q.fresh?(fresh_env)).to be_falsey
241
+ expect(ref_x.fresh?(fresh_env)).to be_falsey
242
+ expect(result.car).to eq(pod)
243
+ end
244
+ end # context
245
+ end # describe
246
+ end # module
247
+ end # module