mini_kraken 0.1.06 → 0.1.11
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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -1
- data/CHANGELOG.md +56 -1
- data/README.md +11 -3
- data/lib/mini_kraken/core/association_walker.rb +1 -1
- data/lib/mini_kraken/core/base_arg.rb +10 -0
- data/lib/mini_kraken/core/conj2.rb +58 -65
- data/lib/mini_kraken/core/cons_cell.rb +49 -43
- data/lib/mini_kraken/core/def_relation.rb +49 -0
- data/lib/mini_kraken/core/disj2.rb +72 -0
- data/lib/mini_kraken/core/duck_fiber.rb +1 -1
- data/lib/mini_kraken/core/environment.rb +1 -1
- data/lib/mini_kraken/core/equals.rb +134 -126
- data/lib/mini_kraken/core/fail.rb +18 -14
- data/lib/mini_kraken/core/formal_arg.rb +22 -0
- data/lib/mini_kraken/core/formal_ref.rb +24 -0
- data/lib/mini_kraken/core/goal_arg.rb +5 -3
- data/lib/mini_kraken/core/goal_relation.rb +13 -0
- data/lib/mini_kraken/core/goal_template.rb +60 -0
- data/lib/mini_kraken/core/k_boolean.rb +31 -0
- data/lib/mini_kraken/core/outcome.rb +40 -24
- data/lib/mini_kraken/core/succeed.rb +17 -13
- data/lib/mini_kraken/core/vocabulary.rb +37 -17
- data/lib/mini_kraken/glue/fresh_env.rb +45 -3
- data/lib/mini_kraken/glue/run_star_expression.rb +45 -19
- data/lib/mini_kraken/version.rb +1 -1
- data/spec/core/conj2_spec.rb +8 -9
- data/spec/core/cons_cell_spec.rb +8 -0
- data/spec/core/def_relation_spec.rb +96 -0
- data/spec/core/disj2_spec.rb +99 -0
- data/spec/core/duck_fiber_spec.rb +12 -1
- data/spec/core/equals_spec.rb +3 -3
- data/spec/core/goal_template_spec.rb +74 -0
- data/spec/core/k_boolean_spec.rb +107 -0
- data/spec/core/outcome_spec.rb +48 -0
- data/spec/core/vocabulary_spec.rb +11 -5
- data/spec/glue/fresh_env_spec.rb +27 -1
- data/spec/glue/run_star_expression_spec.rb +538 -70
- data/spec/mini_kraken_spec.rb +2 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/support/factory_methods.rb +17 -1
- metadata +19 -2
@@ -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
|
@@ -79,11 +79,11 @@ module MiniKraken
|
|
79
79
|
|
80
80
|
it 'should provide a walker over ancestors' do
|
81
81
|
walker = subject.ancestor_walker
|
82
|
-
expect(walker).to be_kind_of(
|
83
|
-
expect(walker.
|
84
|
-
expect(walker.
|
85
|
-
expect(walker.
|
86
|
-
expect(walker.
|
82
|
+
expect(walker).to be_kind_of(Enumerator)
|
83
|
+
expect(walker.next).to eq(subject)
|
84
|
+
expect(walker.next).to eq(mother)
|
85
|
+
expect(walker.next).to eq(grandma)
|
86
|
+
expect(walker.next).to be_nil
|
87
87
|
end
|
88
88
|
|
89
89
|
it 'should know if a variable is defined' do
|
@@ -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
|
data/spec/glue/fresh_env_spec.rb
CHANGED
@@ -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 '
|
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
|
|
@@ -3,8 +3,13 @@
|
|
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/conj2'
|
6
|
+
require_relative '../../lib/mini_kraken/core/def_relation'
|
7
|
+
require_relative '../../lib/mini_kraken/core/disj2'
|
6
8
|
require_relative '../../lib/mini_kraken/core/equals'
|
7
9
|
require_relative '../../lib/mini_kraken/core/fail'
|
10
|
+
require_relative '../../lib/mini_kraken/core/formal_arg'
|
11
|
+
require_relative '../../lib/mini_kraken/core/formal_ref'
|
12
|
+
require_relative '../../lib/mini_kraken/core/goal_template'
|
8
13
|
require_relative '../../lib/mini_kraken/core/succeed'
|
9
14
|
|
10
15
|
require_relative '../support/factory_methods'
|
@@ -20,16 +25,26 @@ module MiniKraken
|
|
20
25
|
let(:pea) { k_symbol(:pea) }
|
21
26
|
let(:pod) { k_symbol(:pod) }
|
22
27
|
let(:sample_goal) { equals_goal(pea, pod) }
|
28
|
+
let(:fails) { Core::Goal.new(Core::Fail.instance, []) }
|
29
|
+
let(:succeeds) { Core::Goal.new(Core::Succeed.instance, []) }
|
23
30
|
subject { RunStarExpression.new('q', sample_goal) }
|
24
31
|
|
25
32
|
context 'Initialization:' do
|
26
|
-
it '
|
33
|
+
it 'could be initialized with a name and a goal' do
|
27
34
|
expect { RunStarExpression.new('q', sample_goal) }.not_to raise_error
|
28
35
|
end
|
29
36
|
|
37
|
+
it 'could be initialized with multiple names and a goal' do
|
38
|
+
expect { RunStarExpression.new(%w[r x y], sample_goal) }.not_to raise_error
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'could be initialized with multiple names and goals' do
|
42
|
+
expect { RunStarExpression.new(%w[r x y], [succeeds, succeeds]) }.not_to raise_error
|
43
|
+
end
|
44
|
+
|
30
45
|
it 'should know its variables' do
|
31
46
|
expect(subject.env.vars['q']).not_to be_nil
|
32
|
-
expect(subject.
|
47
|
+
expect(subject.env.vars.values[0].name).to eq('q')
|
33
48
|
end
|
34
49
|
|
35
50
|
it 'should know its goal' do
|
@@ -38,16 +53,37 @@ module MiniKraken
|
|
38
53
|
end # context
|
39
54
|
|
40
55
|
context 'Provided services:' do
|
56
|
+
let(:k_false) { k_boolean(false) }
|
57
|
+
let(:k_true) { k_boolean(true) }
|
58
|
+
let(:bean) { k_symbol(:bean) }
|
41
59
|
let(:corn) { k_symbol(:corn) }
|
60
|
+
let(:cup) { k_symbol(:cup) }
|
42
61
|
let(:meal) { k_symbol(:meal) }
|
62
|
+
let(:oil) { k_symbol(:oil) }
|
63
|
+
let(:olive) { k_symbol(:olive) }
|
64
|
+
let(:red) { k_symbol(:red) }
|
65
|
+
let(:soup) { k_symbol(:soup) }
|
66
|
+
let(:split) { k_symbol(:split) }
|
67
|
+
let(:tea) { k_symbol(:tea) }
|
68
|
+
let(:virgin) { k_symbol(:virgin) }
|
43
69
|
let(:ref_q) { Core::VariableRef.new('q') }
|
70
|
+
let(:ref_r) { Core::VariableRef.new('r') }
|
44
71
|
let(:ref_x) { Core::VariableRef.new('x') }
|
45
72
|
let(:ref_y) { Core::VariableRef.new('y') }
|
46
73
|
let(:ref_s) { Core::VariableRef.new('s') }
|
47
74
|
let(:ref_t) { Core::VariableRef.new('t') }
|
48
75
|
let(:ref_u) { Core::VariableRef.new('u') }
|
49
|
-
let(:
|
50
|
-
let(:
|
76
|
+
let(:ref_z) { Core::VariableRef.new('z') }
|
77
|
+
let(:t_ref) { Core::FormalRef.new('t') }
|
78
|
+
let(:equals_tea) { Core::GoalTemplate.new(Core::Equals.instance, [tea, t_ref]) }
|
79
|
+
let(:equals_cup) { Core::GoalTemplate.new(Core::Equals.instance, [cup, t_ref]) }
|
80
|
+
let(:g_template) { Core::GoalTemplate.new(Core::Disj2.instance, [equals_tea, equals_cup]) }
|
81
|
+
let(:formal_t) { Core::FormalArg.new('t') }
|
82
|
+
|
83
|
+
# Reasoned S2, frame 1:82
|
84
|
+
# (defrel (teacupo t)
|
85
|
+
# (disj2 (== 'tea t) (== 'cup t)))
|
86
|
+
let(:teacupo_rel) { Core::DefRelation.new('teacupo', g_template, [formal_t]) }
|
51
87
|
|
52
88
|
it 'should return a null list with the fail goal' do
|
53
89
|
# Reasoned S2, frame 1:7
|
@@ -56,7 +92,6 @@ module MiniKraken
|
|
56
92
|
instance = RunStarExpression.new('q', failing)
|
57
93
|
|
58
94
|
expect(instance.run).to be_null
|
59
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
60
95
|
end
|
61
96
|
|
62
97
|
it 'should return a null list when a goal fails' do
|
@@ -74,7 +109,6 @@ module MiniKraken
|
|
74
109
|
# Reasoned S2, frame 1:11
|
75
110
|
# (run* q (== q 'pea) ;; => (pea)
|
76
111
|
expect(instance.run.car).to eq(pea)
|
77
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
78
112
|
end
|
79
113
|
|
80
114
|
it 'should unify the righthand variable(s)' do
|
@@ -84,19 +118,14 @@ module MiniKraken
|
|
84
118
|
# Reasoned S2, frame 1:12
|
85
119
|
# (run* q (== 'pea q) ;; => (pea)
|
86
120
|
expect(instance.run.car).to eq(pea)
|
87
|
-
|
88
|
-
# Reasoned S2, frame 1:15
|
89
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
90
121
|
end
|
91
122
|
|
92
123
|
it 'should return a null list with the succeed goal' do
|
93
|
-
|
94
|
-
instance = RunStarExpression.new('q', success)
|
124
|
+
instance = RunStarExpression.new('q', succeeds)
|
95
125
|
|
96
126
|
# (display (run* q succeed)) ;; => (_0)
|
97
127
|
# Reasoned S2, frame 1:16
|
98
128
|
result = instance.run
|
99
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
100
129
|
|
101
130
|
# Reasoned S2, frame 1:17
|
102
131
|
expect(result.car).to eq(any_value(0))
|
@@ -109,7 +138,6 @@ module MiniKraken
|
|
109
138
|
# (display (run* q (== 'pea 'pea))) ;; => (_0)
|
110
139
|
# Reasoned S2, frame 1:19
|
111
140
|
result = instance.run
|
112
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
113
141
|
expect(result.car).to eq(any_value(0))
|
114
142
|
end
|
115
143
|
|
@@ -122,7 +150,6 @@ module MiniKraken
|
|
122
150
|
# (display (run* q (== q q))) ;; => (_0)
|
123
151
|
# Reasoned S2, frame 1:20
|
124
152
|
result = instance.run
|
125
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
126
153
|
expect(result.car).to eq(any_value(0))
|
127
154
|
end
|
128
155
|
|
@@ -134,8 +161,6 @@ module MiniKraken
|
|
134
161
|
# Reasoned S2, frame 1:21..23
|
135
162
|
# (run* q (fresh (x) (== 'pea q))) ;; => (pea)
|
136
163
|
result = instance.run
|
137
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
138
|
-
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
139
164
|
|
140
165
|
# Reasoned S2, frame 1:40
|
141
166
|
expect(ref_q.different_from?(ref_x, fresh_env)).to be_truthy
|
@@ -150,8 +175,6 @@ module MiniKraken
|
|
150
175
|
# Reasoned S2, frame 1:24
|
151
176
|
# (run* q (fresh (x) (== 'pea x))) ;; => (_0)
|
152
177
|
result = instance.run
|
153
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
154
|
-
expect(ref_x.fresh?(fresh_env)).to be_falsey
|
155
178
|
expect(result.car).to eq(any_value(0))
|
156
179
|
end
|
157
180
|
|
@@ -163,8 +186,6 @@ module MiniKraken
|
|
163
186
|
# Reasoned S2, frame 1:25
|
164
187
|
# (run* q (fresh (x) (== (cons x '()) q))) ;; => ((_0))
|
165
188
|
result = instance.run
|
166
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
167
|
-
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
168
189
|
expect(result.car).to eq(cons(any_value(0)))
|
169
190
|
end
|
170
191
|
|
@@ -195,7 +216,6 @@ module MiniKraken
|
|
195
216
|
# Reasoned S2, frame 1:32
|
196
217
|
# (run* q (== '(((pea)) pod) '(((pea)) pod))) ;; => (_0)
|
197
218
|
result = instance.run
|
198
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
199
219
|
expect(result.car).to eq(any_value(0))
|
200
220
|
end
|
201
221
|
|
@@ -209,7 +229,6 @@ module MiniKraken
|
|
209
229
|
# Reasoned S2, frame 1:33
|
210
230
|
# (run* q (== '(((pea)) pod) `(((pea)) ,q))) ;; => ('pod)
|
211
231
|
result = instance.run
|
212
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
213
232
|
expect(result.car).to eq(pod)
|
214
233
|
end
|
215
234
|
|
@@ -222,7 +241,6 @@ module MiniKraken
|
|
222
241
|
# Reasoned S2, frame 1:34
|
223
242
|
# (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pod)
|
224
243
|
result = instance.run
|
225
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
226
244
|
expect(result.car).to eq(pea)
|
227
245
|
end
|
228
246
|
|
@@ -236,8 +254,6 @@ module MiniKraken
|
|
236
254
|
# Reasoned S2, frame 1:35
|
237
255
|
# (run* q (fresh (x) (== '(((,q)) pod) `(((,x)) pod)))) ;; => (_0)
|
238
256
|
result = instance.run
|
239
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
240
|
-
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
241
257
|
expect(result.car).to eq(any_value(0))
|
242
258
|
end
|
243
259
|
|
@@ -251,11 +267,6 @@ module MiniKraken
|
|
251
267
|
instance = RunStarExpression.new('q', fresh_env)
|
252
268
|
|
253
269
|
result = instance.run
|
254
|
-
|
255
|
-
# Does propagate work correctly?
|
256
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy # x isn't defined here
|
257
|
-
expect(ref_q.fresh?(fresh_env)).to be_falsey
|
258
|
-
expect(ref_x.fresh?(fresh_env)).to be_falsey
|
259
270
|
expect(result.car).to eq(pod)
|
260
271
|
end
|
261
272
|
|
@@ -268,9 +279,6 @@ module MiniKraken
|
|
268
279
|
instance = RunStarExpression.new('q', fresh_env)
|
269
280
|
|
270
281
|
result = instance.run
|
271
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy # x isn't defined here
|
272
|
-
expect(ref_q.fresh?(fresh_env)).to be_truthy
|
273
|
-
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
274
282
|
expect(result.car).to eq(cons(any_value(0), cons(any_value(0))))
|
275
283
|
end
|
276
284
|
|
@@ -285,12 +293,6 @@ module MiniKraken
|
|
285
293
|
instance = RunStarExpression.new('q', fresh_env_x)
|
286
294
|
|
287
295
|
result = instance.run
|
288
|
-
expect(ref_q.fresh?(fresh_env_y)).to be_truthy
|
289
|
-
expect(ref_q.bound?(fresh_env_y)).to be_truthy
|
290
|
-
expect(ref_x.fresh?(fresh_env_y)).to be_truthy
|
291
|
-
expect(ref_x.bound?(fresh_env_y)).to be_falsy
|
292
|
-
expect(ref_y.fresh?(fresh_env_y)).to be_truthy
|
293
|
-
expect(ref_y.bound?(fresh_env_y)).to be_falsy
|
294
296
|
|
295
297
|
# y should be fused with x...
|
296
298
|
var_x = fresh_env_y.name2var('x')
|
@@ -314,13 +316,7 @@ module MiniKraken
|
|
314
316
|
instance = RunStarExpression.new('q', fresh_env_x)
|
315
317
|
|
316
318
|
result = instance.run
|
317
|
-
expect(ref_q.fresh?(fresh_env_y)).to be_truthy
|
318
319
|
# q should be bound to '(,x ,y)
|
319
|
-
expect(ref_q.bound?(fresh_env_y)).to be_truthy
|
320
|
-
expect(ref_x.fresh?(fresh_env_y)).to be_truthy
|
321
|
-
expect(ref_x.bound?(fresh_env_y)).to be_falsey
|
322
|
-
expect(ref_y.fresh?(fresh_env_y)).to be_truthy
|
323
|
-
expect(ref_y.bound?(fresh_env_y)).to be_falsey
|
324
320
|
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
325
321
|
end
|
326
322
|
|
@@ -334,13 +330,7 @@ module MiniKraken
|
|
334
330
|
instance = RunStarExpression.new('s', fresh_env_t)
|
335
331
|
|
336
332
|
result = instance.run
|
337
|
-
expect(ref_s.fresh?(fresh_env_u)).to be_truthy
|
338
333
|
# s should be bound to '(,t ,u)
|
339
|
-
expect(ref_s.bound?(fresh_env_u)).to be_truthy
|
340
|
-
expect(ref_t.fresh?(fresh_env_u)).to be_truthy
|
341
|
-
expect(ref_t.bound?(fresh_env_u)).to be_falsey
|
342
|
-
expect(ref_u.fresh?(fresh_env_u)).to be_truthy
|
343
|
-
expect(ref_u.bound?(fresh_env_u)).to be_falsey
|
344
334
|
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
345
335
|
end
|
346
336
|
|
@@ -354,11 +344,7 @@ module MiniKraken
|
|
354
344
|
instance = RunStarExpression.new('q', fresh_env_x)
|
355
345
|
|
356
346
|
result = instance.run
|
357
|
-
expect(ref_q.fresh?(fresh_env_y)).to be_truthy
|
358
347
|
# q should be bound to '(,x ,y, ,x)
|
359
|
-
expect(ref_q.bound?(fresh_env_y)).to be_truthy
|
360
|
-
expect(ref_x.fresh?(fresh_env_y)).to be_truthy
|
361
|
-
expect(ref_y.fresh?(fresh_env_y)).to be_truthy
|
362
348
|
expect(result.car).to eq(cons(any_value(0), cons(any_value(1), cons(any_value(0)))))
|
363
349
|
end
|
364
350
|
|
@@ -369,22 +355,20 @@ module MiniKraken
|
|
369
355
|
# Reasoned S2, frame 1:50
|
370
356
|
# (run* q (conj2 succeed succeed)) ;; => (_0)
|
371
357
|
result = instance.run
|
372
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
373
358
|
expect(result.car).to eq(any_value(0))
|
374
359
|
end
|
375
360
|
|
376
361
|
# TODO: fix erratic RSpec failure
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
#
|
383
|
-
#
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
# end
|
362
|
+
it 'should support conjunction of one succeed and a successful goal' do
|
363
|
+
subgoal = equals_goal(corn, ref_q)
|
364
|
+
goal = conj2_goal(succeeds, subgoal)
|
365
|
+
instance = RunStarExpression.new('q', goal)
|
366
|
+
|
367
|
+
# Reasoned S2, frame 1:51
|
368
|
+
# (run* q (conj2 succeed (== 'corn q)) ;; => ('corn)
|
369
|
+
result = instance.run
|
370
|
+
expect(result.car).to eq(corn)
|
371
|
+
end
|
388
372
|
|
389
373
|
it 'should support conjunction of one fail and a successful goal' do
|
390
374
|
subgoal = equals_goal(corn, ref_q)
|
@@ -394,7 +378,6 @@ module MiniKraken
|
|
394
378
|
# Reasoned S2, frame 1:52
|
395
379
|
# (run* q (conj2 fail (== 'corn q)) ;; => ()
|
396
380
|
expect(instance.run).to be_null
|
397
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
398
381
|
end
|
399
382
|
|
400
383
|
it 'should support conjunction of two contradictory goals' do
|
@@ -406,7 +389,6 @@ module MiniKraken
|
|
406
389
|
# Reasoned S2, frame 1:53
|
407
390
|
# (run* q (conj2 (== 'corn q)(== 'meal q)) ;; => ()
|
408
391
|
expect(instance.run).to be_null
|
409
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
410
392
|
end
|
411
393
|
|
412
394
|
it 'should succeed the conjunction of two identical goals' do
|
@@ -418,9 +400,495 @@ module MiniKraken
|
|
418
400
|
# Reasoned S2, frame 1:54
|
419
401
|
# (run* q (conj2 (== 'corn q)(== 'corn q)) ;; => ('corn)
|
420
402
|
result = instance.run
|
421
|
-
expect(ref_q.fresh?(instance.env)).to be_falsy
|
422
403
|
expect(result.car).to eq(corn)
|
423
404
|
end
|
405
|
+
|
406
|
+
it 'should not yield solution when both disjunction arguments fail' do
|
407
|
+
goal = disj2_goal(fails, fails)
|
408
|
+
instance = RunStarExpression.new('q', goal)
|
409
|
+
|
410
|
+
# Reasoned S2, frame 1:55
|
411
|
+
# (run* q (disj2 fail fail)) ;; => ()
|
412
|
+
expect(instance.run).to be_null
|
413
|
+
end
|
414
|
+
|
415
|
+
it 'should yield solution when first argument succeed' do
|
416
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
|
417
|
+
goal = disj2_goal(subgoal, fails)
|
418
|
+
instance = RunStarExpression.new('q', goal)
|
419
|
+
|
420
|
+
# Reasoned S2, frame 1:56
|
421
|
+
# (run* q (disj2 (== 'olive q) fail)) ;; => ('olive)
|
422
|
+
result = instance.run
|
423
|
+
expect(result.car).to eq(olive)
|
424
|
+
end
|
425
|
+
|
426
|
+
it 'should yield solution when second argument succeed' do
|
427
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
|
428
|
+
goal = disj2_goal(fails, subgoal)
|
429
|
+
instance = RunStarExpression.new('q', goal)
|
430
|
+
|
431
|
+
# Reasoned S2, frame 1:57
|
432
|
+
# (run* q (disj2 fail (== 'oil q))) ;; => (oil)
|
433
|
+
result = instance.run
|
434
|
+
expect(result.car).to eq(oil)
|
435
|
+
end
|
436
|
+
|
437
|
+
it 'should yield solutions when both arguments succeed' do
|
438
|
+
subgoal1 = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
|
439
|
+
subgoal2 = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
|
440
|
+
goal = disj2_goal(subgoal1, subgoal2)
|
441
|
+
instance = RunStarExpression.new('q', goal)
|
442
|
+
|
443
|
+
# Reasoned S2, frame 1:58
|
444
|
+
# (run* q (disj2 (== 'olive q) (== 'oil q))) ;; => (olive oil)
|
445
|
+
result = instance.run
|
446
|
+
expect(result.car).to eq(olive)
|
447
|
+
expect(result.cdr.car).to eq(oil)
|
448
|
+
end
|
449
|
+
|
450
|
+
it 'should support the nesting of variables and disjunction' do
|
451
|
+
# Reasoned S2, frame 1:59
|
452
|
+
# (run* q (fresh (x) (fresh (y) (disj2 (== '( ,x ,y ) q) (== '( ,x ,y ) q)))))
|
453
|
+
# ;; => ((_0 _1) (_0 _1))
|
454
|
+
expr1 = cons(ref_x, cons(ref_y))
|
455
|
+
subgoal1 = equals_goal(expr1, ref_q)
|
456
|
+
expr2 = cons(ref_y, cons(ref_x))
|
457
|
+
subgoal2 = equals_goal(expr2, ref_q)
|
458
|
+
goal = disj2_goal(subgoal1, subgoal2)
|
459
|
+
fresh_env_y = FreshEnv.new(['y'], goal)
|
460
|
+
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
461
|
+
instance = RunStarExpression.new('q', fresh_env_x)
|
462
|
+
|
463
|
+
result = instance.run
|
464
|
+
# q should be bound to '(,x ,y), then to '(,y ,x)
|
465
|
+
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
466
|
+
expect(result.cdr.car).to eq(cons(any_value(0), cons(any_value(1))))
|
467
|
+
end
|
468
|
+
|
469
|
+
it 'should accept nesting of disj2 and conj2 (I)' do
|
470
|
+
conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
471
|
+
conjunction = conj2_goal(conj_subgoal, fails)
|
472
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
473
|
+
goal = disj2_goal(conjunction, subgoal)
|
474
|
+
instance = RunStarExpression.new('x', goal)
|
475
|
+
|
476
|
+
# Reasoned S2, frame 1:62
|
477
|
+
# (run* x (disj2
|
478
|
+
# (conj2 (== 'olive x) fail)
|
479
|
+
# ('oil x))) ;; => (oil)
|
480
|
+
result = instance.run
|
481
|
+
expect(result.car).to eq(oil)
|
482
|
+
end
|
483
|
+
|
484
|
+
it 'should accept nesting of disj2 and conj2 (II)' do
|
485
|
+
conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
486
|
+
conjunction = conj2_goal(conj_subgoal, succeeds)
|
487
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
488
|
+
goal = disj2_goal(conjunction, subgoal)
|
489
|
+
instance = RunStarExpression.new('x', goal)
|
490
|
+
|
491
|
+
# Reasoned S2, frame 1:63
|
492
|
+
# (run* x (disj2
|
493
|
+
# (conj2 (== 'olive x) succeed)
|
494
|
+
# ('oil x))) ;; => (olive oil)
|
495
|
+
result = instance.run
|
496
|
+
expect(result.car).to eq(olive)
|
497
|
+
expect(result.cdr.car).to eq(oil)
|
498
|
+
end
|
499
|
+
|
500
|
+
it 'should accept nesting of disj2 and conj2 (III)' do
|
501
|
+
conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
502
|
+
conjunction = conj2_goal(conj_subgoal, succeeds)
|
503
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
504
|
+
goal = disj2_goal(subgoal, conjunction)
|
505
|
+
instance = RunStarExpression.new('x', goal)
|
506
|
+
|
507
|
+
# Reasoned S2, frame 1:64
|
508
|
+
# (run* x (disj2
|
509
|
+
# ('oil x)
|
510
|
+
# (conj2 (== 'olive x) succeed))) ;; => (oil olive)
|
511
|
+
result = instance.run
|
512
|
+
expect(result.car).to eq(oil)
|
513
|
+
expect(result.cdr.car).to eq(olive)
|
514
|
+
end
|
515
|
+
|
516
|
+
it 'should accept nesting of disj2 and conj2 (IV)' do
|
517
|
+
oil_goal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
518
|
+
disja = disj2_goal(succeeds, oil_goal)
|
519
|
+
olive_goal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
520
|
+
disjb = disj2_goal(olive_goal, disja)
|
521
|
+
virgin_goal = Core::Goal.new(Core::Equals.instance, [virgin, ref_x])
|
522
|
+
conjunction = conj2_goal(virgin_goal, fails)
|
523
|
+
goal = disj2_goal(conjunction, disjb)
|
524
|
+
instance = RunStarExpression.new('x', goal)
|
525
|
+
|
526
|
+
# Reasoned S2, frame 1:65
|
527
|
+
# (run* x (disj2
|
528
|
+
# (conj2(== 'virgin x) fails)
|
529
|
+
# (disj2
|
530
|
+
# (== 'olive x)
|
531
|
+
# (dis2
|
532
|
+
# succeeds
|
533
|
+
# (== 'oil x))))) ;; => (olive _0 oil)
|
534
|
+
result = instance.run
|
535
|
+
expect(result.car).to eq(olive)
|
536
|
+
expect(result.cdr.car).to eq(any_value(0))
|
537
|
+
expect(result.cdr.cdr.car).to eq(oil)
|
538
|
+
end
|
539
|
+
|
540
|
+
it 'should accept nesting fresh, disj2 and conj2 expressions (I)' do
|
541
|
+
subgoal1 = equals_goal(split, ref_x)
|
542
|
+
expr1 = equals_goal(pea, ref_y)
|
543
|
+
expr2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
544
|
+
subgoal2 = conj2_goal(expr1, expr2)
|
545
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
546
|
+
fresh_env_y = FreshEnv.new(['y'], goal)
|
547
|
+
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
548
|
+
instance = RunStarExpression.new('r', fresh_env_x)
|
549
|
+
|
550
|
+
# Reasoned S2, frame 1:67
|
551
|
+
# (run* r
|
552
|
+
# (fresh x
|
553
|
+
# (fresh y
|
554
|
+
# (conj2
|
555
|
+
# (== 'split x)
|
556
|
+
# (conj2
|
557
|
+
# (== 'pea y)
|
558
|
+
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
559
|
+
result = instance.run
|
560
|
+
expect(result.car.car).to eq(split)
|
561
|
+
expect(result.car.cdr.car).to eq(pea)
|
562
|
+
end
|
563
|
+
|
564
|
+
it 'should accept nesting fresh, disj2 and conj2 expressions (II)' do
|
565
|
+
expr1 = equals_goal(split, ref_x)
|
566
|
+
expr2 = equals_goal(pea, ref_y)
|
567
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
568
|
+
subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
569
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
570
|
+
fresh_env_y = FreshEnv.new(['y'], goal)
|
571
|
+
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
572
|
+
instance = RunStarExpression.new('r', fresh_env_x)
|
573
|
+
|
574
|
+
# Reasoned S2, frame 1:68
|
575
|
+
# (run* r
|
576
|
+
# (fresh x
|
577
|
+
# (fresh y
|
578
|
+
# (conj2
|
579
|
+
# (conj2
|
580
|
+
# (== 'split x)
|
581
|
+
# (== 'pea y)
|
582
|
+
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
583
|
+
result = instance.run
|
584
|
+
expect(result.car.car).to eq(split)
|
585
|
+
expect(result.car.cdr.car).to eq(pea)
|
586
|
+
end
|
587
|
+
|
588
|
+
it 'should accept fresh with multiple variables' do
|
589
|
+
expr1 = equals_goal(split, ref_x)
|
590
|
+
expr2 = equals_goal(pea, ref_y)
|
591
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
592
|
+
subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
593
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
594
|
+
fresh_env = FreshEnv.new(%w[x y], goal)
|
595
|
+
instance = RunStarExpression.new('r', fresh_env)
|
596
|
+
|
597
|
+
# Reasoned S2, frame 1:70
|
598
|
+
# (run* r
|
599
|
+
# (fresh (x y)
|
600
|
+
# (conj2
|
601
|
+
# (conj2
|
602
|
+
# (== 'split x)
|
603
|
+
# (== 'pea y)
|
604
|
+
# (== '(,x ,y) r))))) ;; => ((split pea))
|
605
|
+
result = instance.run
|
606
|
+
expect(result.car.car).to eq(split)
|
607
|
+
expect(result.car.cdr.car).to eq(pea)
|
608
|
+
end
|
609
|
+
|
610
|
+
it 'should accept multiple variables' do
|
611
|
+
expr1 = equals_goal(split, ref_x)
|
612
|
+
expr2 = equals_goal(pea, ref_y)
|
613
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
614
|
+
subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
615
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
616
|
+
instance = RunStarExpression.new(%w[r x y], goal)
|
617
|
+
|
618
|
+
# Reasoned S2, frame 1:72
|
619
|
+
# (run* (r x y)
|
620
|
+
# (conj2
|
621
|
+
# (conj2
|
622
|
+
# (== 'split x)
|
623
|
+
# (== 'pea y))
|
624
|
+
# (== '(,x ,y) r))) ;; => (((split pea) split pea))
|
625
|
+
# o
|
626
|
+
# / \
|
627
|
+
# o nil
|
628
|
+
# / \
|
629
|
+
# / \
|
630
|
+
# / \
|
631
|
+
# / \
|
632
|
+
# / \
|
633
|
+
# o o
|
634
|
+
# / \ / \
|
635
|
+
# split o split o
|
636
|
+
# / \ / \
|
637
|
+
# pea nil pea nil
|
638
|
+
result = instance.run
|
639
|
+
expect(result.car.car.car).to eq(split)
|
640
|
+
expect(result.car.car.cdr.car).to eq(pea)
|
641
|
+
expect(result.car.car.cdr.cdr).to be_nil
|
642
|
+
expect(result.car.cdr.car).to eq(split)
|
643
|
+
expect(result.car.cdr.cdr.car).to eq(pea)
|
644
|
+
expect(result.car.cdr.cdr.cdr).to be_nil
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'should allow simplication of expressions' do
|
648
|
+
expr1 = equals_goal(split, ref_x)
|
649
|
+
expr2 = equals_goal(pea, ref_y)
|
650
|
+
goal = conj2_goal(expr1, expr2)
|
651
|
+
instance = RunStarExpression.new(%w[x y], goal)
|
652
|
+
|
653
|
+
# Reasoned S2, frame 1:75
|
654
|
+
# (run* (x y)
|
655
|
+
# (conj2
|
656
|
+
# (== 'split x)
|
657
|
+
# (== 'pea y))) ;; => ((split pea))
|
658
|
+
result = instance.run
|
659
|
+
expect(result.car.car).to eq(split)
|
660
|
+
expect(result.car.cdr.car).to eq(pea)
|
661
|
+
end
|
662
|
+
|
663
|
+
it 'should allow simplication of expressions' do
|
664
|
+
expr1 = equals_goal(split, ref_x)
|
665
|
+
expr2 = equals_goal(pea, ref_y)
|
666
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
667
|
+
expr3 = equals_goal(red, ref_x)
|
668
|
+
expr4 = equals_goal(bean, ref_y)
|
669
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
670
|
+
goal = disj2_goal(subgoal1, subgoal2)
|
671
|
+
instance = RunStarExpression.new(%w[x y], goal)
|
672
|
+
|
673
|
+
# Reasoned S2, frame 1:76
|
674
|
+
# (run* (x y)
|
675
|
+
# (disj2
|
676
|
+
# (conj2 (== 'split x) (== 'pea y))
|
677
|
+
# (conj2 (== 'red x) (== 'bean y)))) ;; => ((split pea)(red bean))
|
678
|
+
result = instance.run
|
679
|
+
expect(result.car.car).to eq(split)
|
680
|
+
expect(result.car.cdr.car).to eq(pea)
|
681
|
+
expect(result.cdr.car.car).to eq(red)
|
682
|
+
expect(result.cdr.car.cdr.car).to eq(bean)
|
683
|
+
end
|
684
|
+
|
685
|
+
it 'should allow nesting a disjunction inside of conjunction' do
|
686
|
+
expr1 = equals_goal(split, ref_x)
|
687
|
+
expr2 = equals_goal(red, ref_x)
|
688
|
+
subgoal1 = disj2_goal(expr1, expr2)
|
689
|
+
subgoal2 = equals_goal(ref_x, ref_y)
|
690
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
691
|
+
instance = RunStarExpression.new(%w[x y], goal)
|
692
|
+
|
693
|
+
# (display (run* (x y)
|
694
|
+
# (conj2
|
695
|
+
# (disj2
|
696
|
+
# (== 'split x)
|
697
|
+
# (== 'red x))
|
698
|
+
# (== x y)))) ;; => ((split split) (red red))
|
699
|
+
result = instance.run
|
700
|
+
expect(result.car.car).to eq(split)
|
701
|
+
expect(result.car.cdr.car).to eq(split)
|
702
|
+
expect(result.cdr.car.cdr.car).to eq(red)
|
703
|
+
end
|
704
|
+
|
705
|
+
it 'should accept fresh with multiple variables' do
|
706
|
+
expr1 = equals_goal(split, ref_x)
|
707
|
+
expr2 = equals_goal(pea, ref_y)
|
708
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
709
|
+
expr3 = equals_goal(red, ref_x)
|
710
|
+
expr4 = equals_goal(bean, ref_y)
|
711
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
712
|
+
subgoal3 = disj2_goal(subgoal1, subgoal2)
|
713
|
+
subgoal4 = equals_goal(cons(ref_x, cons(ref_y, cons(soup))), ref_r)
|
714
|
+
goal = conj2_goal(subgoal3, subgoal4)
|
715
|
+
fresh_env = FreshEnv.new(%w[x y], goal)
|
716
|
+
instance = RunStarExpression.new('r', fresh_env)
|
717
|
+
|
718
|
+
# Reasoned S2, frame 1:77
|
719
|
+
# (run* r
|
720
|
+
# (fresh (x y)
|
721
|
+
# (conj2
|
722
|
+
# (disj2
|
723
|
+
# (conj2 (== 'split x) (== 'pea y))
|
724
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
725
|
+
# (== '(,x ,y soup) r)))) ;; => ((split pea soup) (red bean soup))
|
726
|
+
result = instance.run
|
727
|
+
expect(result.car.car).to eq(split)
|
728
|
+
expect(result.car.cdr.car).to eq(pea)
|
729
|
+
expect(result.car.cdr.cdr.car).to eq(soup)
|
730
|
+
expect(result.cdr.car.car).to eq(red)
|
731
|
+
expect(result.cdr.car.cdr.car).to eq(bean)
|
732
|
+
expect(result.cdr.car.cdr.cdr.car).to eq(soup)
|
733
|
+
end
|
734
|
+
|
735
|
+
it 'should allow fresh with multiple goals' do
|
736
|
+
expr1 = equals_goal(split, ref_x)
|
737
|
+
expr2 = equals_goal(pea, ref_y)
|
738
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
739
|
+
expr3 = equals_goal(red, ref_x)
|
740
|
+
expr4 = equals_goal(bean, ref_y)
|
741
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
742
|
+
goal1 = disj2_goal(subgoal1, subgoal2)
|
743
|
+
goal2 = equals_goal(cons(ref_x, cons(ref_y, cons(soup))), ref_r)
|
744
|
+
fresh_env = FreshEnv.new(%w[x y], [goal1, goal2])
|
745
|
+
instance = RunStarExpression.new('r', fresh_env)
|
746
|
+
|
747
|
+
# Reasoned S2, frame 1:78
|
748
|
+
# (run* r
|
749
|
+
# (fresh (x y)
|
750
|
+
# (disj2
|
751
|
+
# (conj2 (== 'split x) (== 'pea y))
|
752
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
753
|
+
# (== '(,x ,y soup) r))) ;; => ((split pea soup) (red bean soup))
|
754
|
+
result = instance.run
|
755
|
+
expect(result.car.car).to eq(split)
|
756
|
+
expect(result.car.cdr.car).to eq(pea)
|
757
|
+
expect(result.car.cdr.cdr.car).to eq(soup)
|
758
|
+
expect(result.cdr.car.car).to eq(red)
|
759
|
+
expect(result.cdr.car.cdr.car).to eq(bean)
|
760
|
+
expect(result.cdr.car.cdr.cdr.car).to eq(soup)
|
761
|
+
end
|
762
|
+
|
763
|
+
it 'should allow run* with multiple goals' do
|
764
|
+
expr1 = equals_goal(split, ref_x)
|
765
|
+
expr2 = equals_goal(pea, ref_y)
|
766
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
767
|
+
expr3 = equals_goal(red, ref_x)
|
768
|
+
expr4 = equals_goal(bean, ref_y)
|
769
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
770
|
+
goal1 = disj2_goal(subgoal1, subgoal2)
|
771
|
+
goal2 = equals_goal(soup, ref_z)
|
772
|
+
instance = RunStarExpression.new(%w[x y z], [goal1, goal2])
|
773
|
+
|
774
|
+
# Reasoned S2, frame 1:80
|
775
|
+
# (run* (x y z)
|
776
|
+
# (disj2
|
777
|
+
# (conj2 (== 'split x) (== 'pea y))
|
778
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
779
|
+
# (== 'soup z)) ;; => ((split pea soup) (red bean soup))
|
780
|
+
result = instance.run
|
781
|
+
expect(result.car.car).to eq(split)
|
782
|
+
expect(result.car.cdr.car).to eq(pea)
|
783
|
+
expect(result.car.cdr.cdr.car).to eq(soup)
|
784
|
+
expect(result.cdr.car.car).to eq(red)
|
785
|
+
expect(result.cdr.car.cdr.car).to eq(bean)
|
786
|
+
expect(result.cdr.car.cdr.cdr.car).to eq(soup)
|
787
|
+
end
|
788
|
+
|
789
|
+
it 'should allow simplified expressions with multiple goals' do
|
790
|
+
expr1 = equals_goal(split, ref_x)
|
791
|
+
expr2 = equals_goal(pea, ref_y)
|
792
|
+
instance = RunStarExpression.new(%w[x y], [expr1, expr2])
|
793
|
+
|
794
|
+
# Reasoned S2, frame 1:81
|
795
|
+
# (run* (x y)
|
796
|
+
# (== 'split x)
|
797
|
+
# (== 'pea y)) ;; => ((split pea))
|
798
|
+
result = instance.run
|
799
|
+
expect(result.car.car).to eq(split)
|
800
|
+
expect(result.car.cdr.car).to eq(pea)
|
801
|
+
end
|
802
|
+
|
803
|
+
it 'should solve expression with defrel' do
|
804
|
+
teacupo_goal = Core::Goal.new(teacupo_rel, [ref_x])
|
805
|
+
|
806
|
+
# Reasoned S2, frame 1:83
|
807
|
+
# (run* x
|
808
|
+
# (teacupo x)) ;; => ((tea cup))
|
809
|
+
instance = RunStarExpression.new('x', teacupo_goal)
|
810
|
+
|
811
|
+
result = instance.run
|
812
|
+
expect(result.car).to eq(tea)
|
813
|
+
expect(result.cdr.car).to eq(cup)
|
814
|
+
end
|
815
|
+
|
816
|
+
it 'should solve expression with defrel and booleans' do
|
817
|
+
teacupo_goal = Core::Goal.new(teacupo_rel, [ref_x])
|
818
|
+
expr2 = equals_goal(k_true, ref_y)
|
819
|
+
subgoal1 = conj2_goal(teacupo_goal, expr2)
|
820
|
+
expr3 = equals_goal(k_false, ref_x)
|
821
|
+
expr4 = equals_goal(k_true, ref_y)
|
822
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
823
|
+
goal = disj2_goal(subgoal1, subgoal2)
|
824
|
+
# Reasoned S2, frame 1:84
|
825
|
+
# (run* (x y)
|
826
|
+
# (disj2
|
827
|
+
# (conj2 (teacupo x) (== #t y))
|
828
|
+
# (conj2 (== #f x) (== #t y))) ;; => ((#f #t)(tea #t) (cup #t))
|
829
|
+
instance = RunStarExpression.new(%w[x y], goal)
|
830
|
+
|
831
|
+
result = instance.run
|
832
|
+
# Order of solutions differs from RS book
|
833
|
+
expect(result.car).to eq(cons(tea, cons(true)))
|
834
|
+
expect(result.cdr.car).to eq(cons(cup, cons(true)))
|
835
|
+
expect(result.cdr.cdr.car).to eq(cons(false, cons(true)))
|
836
|
+
end
|
837
|
+
|
838
|
+
it 'should solve expression with two variable and defrel' do
|
839
|
+
teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
|
840
|
+
teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_y])
|
841
|
+
|
842
|
+
# Reasoned S2, frame 1:85
|
843
|
+
# (run* (x y)
|
844
|
+
# (teacupo x)
|
845
|
+
# (teacupo y)) ;; => ((tea tea)(tea cup)(cup tea)(cup c))
|
846
|
+
instance = RunStarExpression.new(%w[x y], [teacupo_goal1, teacupo_goal2])
|
847
|
+
|
848
|
+
result = instance.run
|
849
|
+
expect(result.car).to eq(cons(tea, cons(tea)))
|
850
|
+
expect(result.cdr.car).to eq(cons(tea, cons(cup)))
|
851
|
+
expect(result.cdr.cdr.car).to eq(cons(cup, cons(tea)))
|
852
|
+
expect(result.cdr.cdr.cdr.car).to eq(cons(cup, cons(cup)))
|
853
|
+
end
|
854
|
+
|
855
|
+
it 'should solve expression with two variable and defrel' do
|
856
|
+
teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
|
857
|
+
teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_x])
|
858
|
+
|
859
|
+
# Reasoned S2, frame 1:86
|
860
|
+
# (run* (x y)
|
861
|
+
# (teacupo x)
|
862
|
+
# (teacupo x)) ;; => ((tea _0)(cup _0))
|
863
|
+
instance = RunStarExpression.new(%w[x y], [teacupo_goal1, teacupo_goal2])
|
864
|
+
|
865
|
+
result = instance.run
|
866
|
+
expect(result.car).to eq(cons(tea, cons(any_value(0))))
|
867
|
+
expect(result.cdr.car).to eq(cons(cup, cons(any_value(0))))
|
868
|
+
end
|
869
|
+
|
870
|
+
it 'should solve expression with defrel and booleans' do
|
871
|
+
teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
|
872
|
+
teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_x])
|
873
|
+
subgoal1 = conj2_goal(teacupo_goal1, teacupo_goal2)
|
874
|
+
expr3 = equals_goal(k_false, ref_x)
|
875
|
+
expr4 = Core::Goal.new(teacupo_rel, [ref_y])
|
876
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
877
|
+
goal = disj2_goal(subgoal1, subgoal2)
|
878
|
+
# Reasoned S2, frame 1:87
|
879
|
+
# (run* (x y)
|
880
|
+
# (disj2
|
881
|
+
# (conj2 (teacupo x) (teacupo x))
|
882
|
+
# (conj2 (== #f x) (teacupo y)))) ;; => ((#f tea)(#f cup)(tea _0)(cup _0))
|
883
|
+
instance = RunStarExpression.new(%w[x y], goal)
|
884
|
+
|
885
|
+
result = instance.run
|
886
|
+
# Order of solutions differs from RS book
|
887
|
+
expect(result.car).to eq(cons(tea, cons(any_value(0))))
|
888
|
+
expect(result.cdr.car).to eq(cons(cup, cons(any_value(0))))
|
889
|
+
expect(result.cdr.cdr.car).to eq(cons(false, cons(tea)))
|
890
|
+
expect(result.cdr.cdr.cdr.car).to eq(cons(false, cons(cup)))
|
891
|
+
end
|
424
892
|
end # context
|
425
893
|
end # describe
|
426
894
|
end # module
|