mini_kraken 0.1.01 → 0.1.02

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 (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