mini_kraken 0.1.12 → 0.2.03
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/.rubocop.yml +334 -0
- data/CHANGELOG.md +54 -0
- data/README.md +95 -13
- data/lib/mini_kraken.rb +7 -1
- data/lib/mini_kraken/core/any_value.rb +5 -1
- data/lib/mini_kraken/core/atomic_term.rb +1 -0
- data/lib/mini_kraken/core/conde.rb +1 -1
- data/lib/mini_kraken/core/conj2.rb +3 -3
- data/lib/mini_kraken/core/cons_cell.rb +29 -1
- data/lib/mini_kraken/core/cons_cell_visitor.rb +102 -0
- data/lib/mini_kraken/core/def_relation.rb +4 -0
- data/lib/mini_kraken/core/disj2.rb +2 -2
- data/lib/mini_kraken/core/environment.rb +2 -2
- data/lib/mini_kraken/core/equals.rb +60 -26
- data/lib/mini_kraken/core/formal_ref.rb +2 -1
- data/lib/mini_kraken/core/goal.rb +4 -2
- data/lib/mini_kraken/core/goal_template.rb +44 -2
- data/lib/mini_kraken/core/k_boolean.rb +4 -0
- data/lib/mini_kraken/core/k_symbol.rb +11 -0
- data/lib/mini_kraken/core/outcome.rb +11 -1
- data/lib/mini_kraken/core/variable.rb +10 -4
- data/lib/mini_kraken/core/variable_ref.rb +7 -0
- data/lib/mini_kraken/core/vocabulary.rb +8 -3
- data/lib/mini_kraken/glue/dsl.rb +236 -0
- data/lib/mini_kraken/glue/fresh_env.rb +31 -3
- data/lib/mini_kraken/glue/fresh_env_factory.rb +83 -0
- data/lib/mini_kraken/glue/run_star_expression.rb +3 -5
- data/lib/mini_kraken/version.rb +1 -1
- data/mini_kraken.gemspec +6 -3
- data/spec/.rubocop.yml +13 -0
- data/spec/core/conde_spec.rb +10 -10
- data/spec/core/conj2_spec.rb +7 -7
- data/spec/core/cons_cell_spec.rb +35 -0
- data/spec/core/cons_cell_visitor_spec.rb +144 -0
- data/spec/core/def_relation_spec.rb +6 -5
- data/spec/core/disj2_spec.rb +5 -5
- data/spec/core/duck_fiber_spec.rb +2 -2
- data/spec/core/equals_spec.rb +34 -21
- data/spec/core/goal_spec.rb +2 -2
- data/spec/core/k_boolean_spec.rb +6 -0
- data/spec/core/k_symbol_spec.rb +4 -0
- data/spec/core/outcome_spec.rb +8 -0
- data/spec/core/variable_ref_spec.rb +3 -0
- data/spec/glue/dsl_chap1_spec.rb +679 -0
- data/spec/glue/dsl_chap2_spec.rb +100 -0
- data/spec/glue/fresh_env_factory_spec.rb +97 -0
- data/spec/glue/run_star_expression_spec.rb +11 -11
- metadata +17 -4
@@ -17,6 +17,7 @@ require_relative '../../lib/mini_kraken/core/def_relation'
|
|
17
17
|
module MiniKraken
|
18
18
|
module Core
|
19
19
|
describe DefRelation do
|
20
|
+
# (defrel (teao t) (== 'tea t))
|
20
21
|
let(:tea) { KSymbol.new(:tea) }
|
21
22
|
let(:formal_t) { FormalArg.new('t') }
|
22
23
|
let(:t_ref) { FormalRef.new('t') }
|
@@ -53,13 +54,13 @@ module MiniKraken
|
|
53
54
|
defrel = DefRelation.new('teao', equals_tea, [formal_t])
|
54
55
|
solver = defrel.solver_for([tea], env)
|
55
56
|
outcome = solver.resume
|
56
|
-
expect(outcome).to
|
57
|
+
expect(outcome).to be_success
|
57
58
|
outcome = solver.resume
|
58
59
|
expect(outcome).to be_nil
|
59
60
|
|
60
61
|
solver = defrel.solver_for([cup], env)
|
61
62
|
outcome = solver.resume
|
62
|
-
expect(outcome).not_to
|
63
|
+
expect(outcome).not_to be_success
|
63
64
|
outcome = solver.resume
|
64
65
|
expect(outcome).to be_nil
|
65
66
|
end
|
@@ -69,7 +70,7 @@ module MiniKraken
|
|
69
70
|
env.add_var(Variable.new('x'))
|
70
71
|
solver = defrel.solver_for([ref_x], env)
|
71
72
|
outcome = solver.resume
|
72
|
-
expect(outcome).to
|
73
|
+
expect(outcome).to be_success
|
73
74
|
expect(ref_x.value(outcome)).to eq(tea)
|
74
75
|
|
75
76
|
outcome = solver.resume
|
@@ -80,11 +81,11 @@ module MiniKraken
|
|
80
81
|
env.add_var(Variable.new('x'))
|
81
82
|
solver = subject.solver_for([ref_x], env)
|
82
83
|
outcome = solver.resume
|
83
|
-
expect(outcome).to
|
84
|
+
expect(outcome).to be_success
|
84
85
|
expect(ref_x.value(outcome)).to eq(tea)
|
85
86
|
|
86
87
|
outcome = solver.resume
|
87
|
-
expect(outcome).to
|
88
|
+
expect(outcome).to be_success
|
88
89
|
expect(ref_x.value(outcome)).to eq(cup)
|
89
90
|
|
90
91
|
outcome = solver.resume
|
data/spec/core/disj2_spec.rb
CHANGED
@@ -52,7 +52,7 @@ module MiniKraken
|
|
52
52
|
it 'should fails if both arguments fail' do
|
53
53
|
# Covers frame 1:55
|
54
54
|
solver = subject.solver_for([fails, fails], env)
|
55
|
-
expect(solver.resume).not_to
|
55
|
+
expect(solver.resume).not_to be_success
|
56
56
|
expect(solver.resume).to be_nil
|
57
57
|
end
|
58
58
|
|
@@ -61,7 +61,7 @@ module MiniKraken
|
|
61
61
|
subgoal = Goal.new(Equals.instance, [olive, ref_q])
|
62
62
|
solver = subject.solver_for([subgoal, fails], env)
|
63
63
|
outcome = solver.resume
|
64
|
-
expect(outcome).to
|
64
|
+
expect(outcome).to be_success
|
65
65
|
expect(outcome.associations['q'].first.value).to eq(olive)
|
66
66
|
expect(solver.resume).to be_nil
|
67
67
|
end
|
@@ -71,7 +71,7 @@ module MiniKraken
|
|
71
71
|
subgoal = Goal.new(Equals.instance, [oil, ref_q])
|
72
72
|
solver = subject.solver_for([fails, subgoal], env)
|
73
73
|
outcome = solver.resume
|
74
|
-
expect(outcome).to
|
74
|
+
expect(outcome).to be_success
|
75
75
|
expect(outcome.associations['q'].first.value).to eq(oil)
|
76
76
|
expect(solver.resume).to be_nil
|
77
77
|
end
|
@@ -84,12 +84,12 @@ module MiniKraken
|
|
84
84
|
|
85
85
|
# First solution
|
86
86
|
outcome1 = solver.resume
|
87
|
-
expect(outcome1).to
|
87
|
+
expect(outcome1).to be_success
|
88
88
|
expect(outcome1.associations['q'].first.value).to eq(olive)
|
89
89
|
|
90
90
|
# Second solution
|
91
91
|
outcome2 = solver.resume
|
92
|
-
expect(outcome2).to
|
92
|
+
expect(outcome2).to be_success
|
93
93
|
expect(outcome2.associations['q'].first.value).to eq(oil)
|
94
94
|
expect(solver.resume).to be_nil
|
95
95
|
end
|
@@ -40,7 +40,7 @@ module MiniKraken
|
|
40
40
|
succeeding = DuckFiber.new(:success)
|
41
41
|
outcome = nil
|
42
42
|
expect { outcome = succeeding.resume }.not_to raise_error
|
43
|
-
expect(outcome).to
|
43
|
+
expect(outcome).to be_success
|
44
44
|
expect(outcome.parent).to be_nil
|
45
45
|
|
46
46
|
# Only one result should be yielded
|
@@ -52,7 +52,7 @@ module MiniKraken
|
|
52
52
|
outcome1 = instance1.resume
|
53
53
|
|
54
54
|
instance2 = DuckFiber.new(:success)
|
55
|
-
outcome2 =
|
55
|
+
outcome2 = instance2.resume
|
56
56
|
|
57
57
|
expect(outcome1).not_to be_equal(outcome2)
|
58
58
|
end
|
data/spec/core/equals_spec.rb
CHANGED
@@ -106,7 +106,7 @@ module MiniKraken
|
|
106
106
|
it 'should succeed for a right-handed fresh argument' do
|
107
107
|
result = solve_for(pea, ref_q)
|
108
108
|
|
109
|
-
expect(result).to
|
109
|
+
expect(result).to be_success
|
110
110
|
expect(env.associations.size).to eq(1)
|
111
111
|
expect(env.associations['q'].first.value).to eq(pea)
|
112
112
|
expect(var_q.fresh?(result)).to be_falsey
|
@@ -116,7 +116,7 @@ module MiniKraken
|
|
116
116
|
it 'should succeed for a left-handed fresh argument' do
|
117
117
|
result = solve_for(ref_q, pea)
|
118
118
|
|
119
|
-
expect(result).to
|
119
|
+
expect(result).to be_success
|
120
120
|
expect(env.associations.size).to eq(1)
|
121
121
|
expect(env.associations['q'].first.value).to eq(pea)
|
122
122
|
expect(var_q.fresh?(result)).to be_falsey
|
@@ -127,7 +127,7 @@ module MiniKraken
|
|
127
127
|
ref_q.associate(pod, env)
|
128
128
|
|
129
129
|
result = solve_for(pod, ref_q)
|
130
|
-
expect(result).to
|
130
|
+
expect(result).to be_success
|
131
131
|
expect(env.associations.size).to eq(1) # No new association
|
132
132
|
expect(ref_q.fresh?(result)).not_to be_truthy
|
133
133
|
expect(ref_q.values(result).first).to eq(pod)
|
@@ -137,7 +137,7 @@ module MiniKraken
|
|
137
137
|
ref_q.associate(pod, env)
|
138
138
|
|
139
139
|
result = solve_for(ref_q, pod)
|
140
|
-
expect(result).to
|
140
|
+
expect(result).to be_success
|
141
141
|
expect(result.associations).to be_empty
|
142
142
|
expect(ref_q.fresh?(result)).to be_falsey
|
143
143
|
expect(ref_q.values(result).first).to eq(pod)
|
@@ -147,7 +147,7 @@ module MiniKraken
|
|
147
147
|
ref_q.associate(pod, env)
|
148
148
|
|
149
149
|
result = solve_for(pea, ref_q)
|
150
|
-
expect(result).not_to
|
150
|
+
expect(result).not_to be_success
|
151
151
|
expect(result.associations).to be_empty
|
152
152
|
expect(ref_q.fresh?(result)).to be_falsey
|
153
153
|
expect(ref_q.values(result).first).to eq(pod)
|
@@ -157,7 +157,7 @@ module MiniKraken
|
|
157
157
|
ref_q.associate(pod, env)
|
158
158
|
|
159
159
|
result = solve_for(ref_q, pea)
|
160
|
-
expect(result).not_to
|
160
|
+
expect(result).not_to be_success
|
161
161
|
expect(result.associations).to be_empty
|
162
162
|
expect(ref_q.fresh?(result)).to be_falsey
|
163
163
|
expect(ref_q.values(result).first).to eq(pod)
|
@@ -166,7 +166,7 @@ module MiniKraken
|
|
166
166
|
it 'should succeed for a composite and right-handed fresh argument' do
|
167
167
|
result = solve_for(sample_cons, ref_q)
|
168
168
|
|
169
|
-
expect(result).to
|
169
|
+
expect(result).to be_success
|
170
170
|
expect(env.associations.size).to eq(1)
|
171
171
|
expect(ref_q.fresh?(result)).to be_falsey
|
172
172
|
expect(ref_q.values(result).first).to eq(sample_cons)
|
@@ -175,7 +175,7 @@ module MiniKraken
|
|
175
175
|
it 'should succeed for composite and left-handed fresh argument' do
|
176
176
|
result = solve_for(ref_q, sample_cons)
|
177
177
|
|
178
|
-
expect(result).to
|
178
|
+
expect(result).to be_success
|
179
179
|
expect(env.associations.size).to eq(1)
|
180
180
|
expect(ref_q.fresh?(result)).to be_falsey
|
181
181
|
expect(ref_q.values(result).first).to eq(sample_cons)
|
@@ -186,7 +186,7 @@ module MiniKraken
|
|
186
186
|
composite = ConsCell.new(pea)
|
187
187
|
result = solve_for(composite, ref_q)
|
188
188
|
|
189
|
-
expect(result).to
|
189
|
+
expect(result).to be_success
|
190
190
|
expect(result.associations).to be_empty
|
191
191
|
expect(ref_q.fresh?(result)).not_to be_truthy
|
192
192
|
expect(ref_q.values(result).first).to eq(sample_cons)
|
@@ -197,7 +197,7 @@ module MiniKraken
|
|
197
197
|
composite = ConsCell.new(pea)
|
198
198
|
result = solve_for(ref_q, composite)
|
199
199
|
|
200
|
-
expect(result).to
|
200
|
+
expect(result).to be_success
|
201
201
|
expect(result.associations).to be_empty
|
202
202
|
expect(ref_q.fresh?(result)).not_to be_truthy
|
203
203
|
expect(ref_q.values(result).first).to eq(sample_cons)
|
@@ -208,7 +208,7 @@ module MiniKraken
|
|
208
208
|
composite = ConsCell.new(pod)
|
209
209
|
result = solve_for(composite, ref_q)
|
210
210
|
|
211
|
-
expect(result).
|
211
|
+
expect(result).to be_failure
|
212
212
|
expect(result.associations).to be_empty
|
213
213
|
expect(ref_q.fresh?(result)).not_to be_truthy
|
214
214
|
expect(ref_q.values(result).first).to eq(sample_cons)
|
@@ -219,7 +219,7 @@ module MiniKraken
|
|
219
219
|
composite = ConsCell.new(pod)
|
220
220
|
result = solve_for(ref_q, composite)
|
221
221
|
|
222
|
-
expect(result).not_to
|
222
|
+
expect(result).not_to be_success
|
223
223
|
expect(result.associations).to be_empty
|
224
224
|
expect(ref_q.fresh?(result)).not_to be_truthy
|
225
225
|
expect(ref_q.values(result).first).to eq(sample_cons)
|
@@ -228,7 +228,7 @@ module MiniKraken
|
|
228
228
|
it 'should succeed for both identical fresh arguments' do
|
229
229
|
result = solve_for(ref_q, ref_q)
|
230
230
|
|
231
|
-
expect(result).to
|
231
|
+
expect(result).to be_success
|
232
232
|
expect(result.associations).to be_empty
|
233
233
|
expect(ref_q.fresh?(result)).to be_truthy
|
234
234
|
end
|
@@ -236,7 +236,7 @@ module MiniKraken
|
|
236
236
|
it 'should succeed for both same fresh arguments' do
|
237
237
|
result = solve_for(ref_q, ref_q_bis)
|
238
238
|
|
239
|
-
expect(result).to
|
239
|
+
expect(result).to be_success
|
240
240
|
expect(result.associations).to be_empty
|
241
241
|
expect(ref_q.fresh?(result)).to be_truthy
|
242
242
|
expect(ref_q_bis.fresh?(result)).to be_truthy
|
@@ -245,7 +245,7 @@ module MiniKraken
|
|
245
245
|
it 'should succeed for both distinct fresh arguments' do
|
246
246
|
result = solve_for(ref_x, ref_y)
|
247
247
|
|
248
|
-
expect(result).to
|
248
|
+
expect(result).to be_success
|
249
249
|
expect(env.associations).to be_empty # Symmetric association
|
250
250
|
expect(ref_x.fresh?(result)).to be_truthy
|
251
251
|
expect(ref_y.fresh?(result)).to be_truthy
|
@@ -258,7 +258,7 @@ module MiniKraken
|
|
258
258
|
expect(ref_y.fresh?(env)).to be_falsey
|
259
259
|
|
260
260
|
result = solve_for(ref_x, ref_y)
|
261
|
-
expect(result).to
|
261
|
+
expect(result).to be_success
|
262
262
|
expect(result.associations).to be_empty
|
263
263
|
end
|
264
264
|
|
@@ -269,19 +269,20 @@ module MiniKraken
|
|
269
269
|
expect(ref_y.fresh?(env)).to be_falsey
|
270
270
|
|
271
271
|
result = solve_for(ref_x, ref_y)
|
272
|
-
expect(result).not_to
|
272
|
+
expect(result).not_to be_success
|
273
273
|
expect(result.associations).to be_empty
|
274
274
|
end
|
275
275
|
|
276
276
|
it 'should unify composite terms with variables' do
|
277
277
|
# Reasoned S2, frame 1:36
|
278
278
|
# (run* q (fresh (x) (== '(((,q)) ,x) `(((,x)) pod)))) ;; => ('pod)
|
279
|
-
expr1 = cons(cons(cons(ref_q)), ref_x)
|
280
|
-
|
279
|
+
expr1 = cons(cons(cons(ref_q)), cons(ref_x))
|
280
|
+
expect(expr1.to_s).to eq('(((q)) x)')
|
281
|
+
expr2 = cons(cons(cons(ref_x)), cons(pod))
|
282
|
+
expect(expr2.to_s).to eq('(((x)) :pod)')
|
281
283
|
|
282
284
|
result = solve_for(expr1, expr2)
|
283
|
-
|
284
|
-
expect(result).to be_successful
|
285
|
+
expect(result).to be_success
|
285
286
|
expect(ref_x.fresh?(env)).to be_falsey
|
286
287
|
expect(ref_q.fresh?(env)).to be_falsey
|
287
288
|
end
|
@@ -298,6 +299,18 @@ module MiniKraken
|
|
298
299
|
expect(result.resultant).to eq(:"#u")
|
299
300
|
expect(result.associations).to be_empty
|
300
301
|
end
|
302
|
+
|
303
|
+
it 'should unify variables with a list' do
|
304
|
+
# Variant of Reasoned S2, frame 2:3
|
305
|
+
# (== (cons q x) '(a c o r n)) ;; q => :a, x => '(c o r n)
|
306
|
+
expr1 = cons(ref_q, ref_x)
|
307
|
+
acorn = cons(k_symbol(:a), cons(k_symbol(:c),
|
308
|
+
cons(k_symbol(:o), cons(k_symbol(:r), cons(k_symbol(:n))))))
|
309
|
+
result = solve_for(expr1, acorn)
|
310
|
+
expect(result.resultant).to eq(:"#s")
|
311
|
+
q_value = env.associations['q'].first.value
|
312
|
+
expect(q_value).to eq(:a)
|
313
|
+
end
|
301
314
|
end # context
|
302
315
|
end # describe
|
303
316
|
end # module
|
data/spec/core/goal_spec.rb
CHANGED
@@ -40,7 +40,7 @@ module MiniKraken
|
|
40
40
|
context 'Provided services:' do
|
41
41
|
it 'should fail if relation does not succeed' do
|
42
42
|
solver = subject.attain(env)
|
43
|
-
expect(solver.resume).not_to
|
43
|
+
expect(solver.resume).not_to be_success
|
44
44
|
|
45
45
|
# No more solution...
|
46
46
|
expect(solver.resume).to be_nil
|
@@ -50,7 +50,7 @@ module MiniKraken
|
|
50
50
|
instance = Goal.new(binary_relation, [KSymbol.new(:pea), KSymbol.new(:pea)])
|
51
51
|
|
52
52
|
solver = instance.attain(env)
|
53
|
-
expect(solver.resume).to
|
53
|
+
expect(solver.resume).to be_success
|
54
54
|
|
55
55
|
# No more solution...
|
56
56
|
expect(solver.resume).to be_nil
|
data/spec/core/k_boolean_spec.rb
CHANGED
@@ -101,6 +101,12 @@ module MiniKraken
|
|
101
101
|
# Default Ruby representation, different value
|
102
102
|
expect(subject == false).to be_falsy
|
103
103
|
end
|
104
|
+
|
105
|
+
it 'provides a text representation of itself' do
|
106
|
+
expect(subject.to_s).to eq('true')
|
107
|
+
other = KBoolean.new('#f')
|
108
|
+
expect(other.to_s).to eq('false')
|
109
|
+
end
|
104
110
|
end # context
|
105
111
|
end # describe
|
106
112
|
end # module
|
data/spec/core/k_symbol_spec.rb
CHANGED
@@ -65,6 +65,10 @@ module MiniKraken
|
|
65
65
|
# Default Ruby representation, different value
|
66
66
|
expect(subject == :pod).to be_falsy
|
67
67
|
end
|
68
|
+
|
69
|
+
it 'should provide a string representation of itself' do
|
70
|
+
expect(subject.to_s).to eq(':pea')
|
71
|
+
end
|
68
72
|
end # context
|
69
73
|
end # describe
|
70
74
|
end # module
|
data/spec/core/outcome_spec.rb
CHANGED
@@ -25,6 +25,14 @@ module MiniKraken
|
|
25
25
|
expect(subject.resultant).to eq(:"#s")
|
26
26
|
end
|
27
27
|
|
28
|
+
it 'should know whether it represents a failure' do
|
29
|
+
expect(Outcome.new(:"#u")).to be_failure
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should know whether it represents a success' do
|
33
|
+
expect(subject).to be_success
|
34
|
+
end
|
35
|
+
|
28
36
|
it 'should know its parent' do
|
29
37
|
expect(subject.parent).to eq(voc)
|
30
38
|
end
|
@@ -0,0 +1,679 @@
|
|
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/glue/dsl'
|
7
|
+
|
8
|
+
|
9
|
+
module MiniKraken
|
10
|
+
module Glue
|
11
|
+
describe 'DSL (Chap 1)' do
|
12
|
+
include DSL
|
13
|
+
|
14
|
+
context 'Chapter 1 examples:' do
|
15
|
+
it 'passes frame 1:7' do
|
16
|
+
# Reasoned S2, frame 1:7
|
17
|
+
# (run* q #u) ;; => ()
|
18
|
+
|
19
|
+
result = run_star('q', _fail)
|
20
|
+
expect(result).to be_null
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'passes frame 1:10' do
|
24
|
+
# Reasoned S2, frame 1:10
|
25
|
+
# (run* q (== 'pea 'pod) ;; => ()
|
26
|
+
|
27
|
+
result = run_star('q', equals(:pea, :pod))
|
28
|
+
expect(result).to be_null
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'passes frame 1:11' do
|
32
|
+
# Reasoned S2, frame 1:11
|
33
|
+
# (run* q (== q 'pea) ;; => (pea)
|
34
|
+
|
35
|
+
result = run_star('q', equals(q, :pea))
|
36
|
+
expect(result.car).to eq(:pea)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'passes frame 1:12' do
|
40
|
+
# Reasoned S2, frame 1:12
|
41
|
+
# (run* q (== 'pea q) ;; => (pea)
|
42
|
+
|
43
|
+
result = run_star('q', equals(:pea, q))
|
44
|
+
expect(result.car).to eq(:pea)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'passes frame 1:17' do
|
48
|
+
# Reasoned S2, frame 1:17
|
49
|
+
# (run* q succeed) ;; => (_0)
|
50
|
+
|
51
|
+
result = run_star('q', succeed)
|
52
|
+
expect(result.car).to eq(:_0)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'passes frame 1:19' do
|
56
|
+
# Reasoned S2, frame 1:19
|
57
|
+
# (run* q (== 'pea 'pea)) ;; => (_0)
|
58
|
+
|
59
|
+
result = run_star('q', equals(:pea, :pea))
|
60
|
+
expect(result.car).to eq(:_0)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'passes frame 1:20' do
|
64
|
+
# Reasoned S2, frame 1:20
|
65
|
+
# (run* q (== q q)) ;; => (_0)
|
66
|
+
|
67
|
+
result = run_star('q', equals(q, q))
|
68
|
+
expect(result.car).to eq(:_0)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "supports 'fresh' and passes frame 1:21" do
|
72
|
+
# Reasoned S2, frame 1:21
|
73
|
+
# (run* q (fresh (x) (== 'pea q))) ;; => (pea)
|
74
|
+
|
75
|
+
result = run_star('q', fresh('x', equals(:pea, q)))
|
76
|
+
expect(result.car).to eq(:pea)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'passes frame 1:25' do
|
80
|
+
# Reasoned S2, frame 1:25
|
81
|
+
# (run* q (fresh (x) (== (cons x '()) q))) ;; => ((_0))
|
82
|
+
# require 'debug' Invalid goal argument
|
83
|
+
result = run_star('q', fresh('x', equals(cons(x, null), q)))
|
84
|
+
expect(result.car).to eq(cons(:_0))
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'passes frame 1:31' do
|
88
|
+
# Reasoned S2, frame 1:31
|
89
|
+
# (run* q (fresh (x) (== x q))) ;; => (_0)
|
90
|
+
|
91
|
+
result = run_star('q', fresh('x', equals(x, q)))
|
92
|
+
expect(result.car).to eq(:_0)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'passes frame 1:32' do
|
96
|
+
# Reasoned S2, frame 1:32
|
97
|
+
# (run* q (== '(((pea)) pod) '(((pea)) pod))) ;; => (_0)
|
98
|
+
|
99
|
+
result = run_star('q', equals(cons(cons(:pea), :pod), cons(cons(:pea), :pod)))
|
100
|
+
expect(result.car).to eq(:_0)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'passes frame 1:33' do
|
104
|
+
# Beware: quasiquoting
|
105
|
+
# Reasoned S2, frame 1:33
|
106
|
+
# (run* q (== '(((pea)) pod) '(((pea)) ,q))) ;; => ('pod)
|
107
|
+
|
108
|
+
result = run_star('q', equals(cons(cons(:pea), :pod), cons(cons(:pea), q)))
|
109
|
+
expect(result.car).to eq(:pod)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'passes frame 1:34' do
|
113
|
+
# Reasoned S2, frame 1:34
|
114
|
+
# (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pea)
|
115
|
+
|
116
|
+
expr1 = cons(cons(cons(q)), cons(:pod))
|
117
|
+
expect(expr1.to_s).to eq('(((q)) :pod)')
|
118
|
+
expr2 = cons(cons(cons(:pea)), cons(:pod))
|
119
|
+
expect(expr2.to_s).to eq('(((:pea)) :pod)')
|
120
|
+
result = run_star('q', equals(expr1, expr2))
|
121
|
+
expect(result.car).to eq(:pea)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'passes frame 1:35' do
|
125
|
+
# Reasoned S2, frame 1:35
|
126
|
+
# (run* q (fresh (x) (== '(((,q)) pod) `(((,x)) pod)))) ;; => (_0)
|
127
|
+
|
128
|
+
result = run_star('q', fresh('x', equals(cons(cons(q), :pod), cons(cons(x), :pod))))
|
129
|
+
expect(result.car).to eq(:_0)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'passes frame 1:36' do
|
133
|
+
# Reasoned S2, frame 1:36
|
134
|
+
# (run* q (fresh (x) (== '(((,q)) ,x) `(((,x)) pod)))) ;; => ('pod)
|
135
|
+
|
136
|
+
expr1 = cons(cons(cons(q)), cons(x))
|
137
|
+
expect(expr1.to_s).to eq('(((q)) x)')
|
138
|
+
expr2 = cons(cons(cons(x)), cons(:pod))
|
139
|
+
expect(expr2.to_s).to eq('(((x)) :pod)')
|
140
|
+
result = run_star('q', fresh('x', equals(expr1, expr2)))
|
141
|
+
expect(result.car).to eq(:pod)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'passes frame 1:37' do
|
145
|
+
# Reasoned S2, frame 1:37
|
146
|
+
# (run* q (fresh (x) (== '( ,x ,x) q))) ;; => (_0 _0)
|
147
|
+
|
148
|
+
result = run_star('q', fresh('x', equals(cons(x, cons(x)), q)))
|
149
|
+
expect(result.car).to eq(cons(:_0, cons(:_0)))
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'passes frame 1:38' do
|
153
|
+
# Reasoned S2, frame 1:38
|
154
|
+
# (run* q (fresh (x) (fresh (y) (== '( ,q ,y) '((,x ,y) ,x))))) ;; => (_0 _0)
|
155
|
+
|
156
|
+
result = run_star('q', fresh('x', fresh('y', equals(cons(q, cons(y)), cons(cons(x, cons(y)), cons(x))))))
|
157
|
+
expect(result.car).to eq(cons(:_0, cons(:_0)))
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'passes frame 1:41' do
|
161
|
+
# Reasoned S2, frame 1:41
|
162
|
+
# (run* q (fresh (x) (fresh (y) (== '( ,x ,y) q)))) ;; => (_0 _1)
|
163
|
+
|
164
|
+
result = run_star('q', fresh('x', fresh('y', equals(cons(x, cons(y)), q))))
|
165
|
+
# q should be bound to '(,x ,y)
|
166
|
+
expect(result.car).to eq(cons(:_0, cons(:_1)))
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'passes frame 1:42' do
|
170
|
+
# Reasoned S2, frame 1:42
|
171
|
+
# (run* s (fresh (t) (fresh (u) (== '( ,t ,u) s)))) ;; => (_0 _1)
|
172
|
+
|
173
|
+
result = run_star('s', fresh('t', fresh('u', equals(cons(t, cons(u)), s))))
|
174
|
+
# s should be bound to '(,t ,u)
|
175
|
+
expect(result.car).to eq(cons(:_0, cons(:_1)))
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'passes frame 1:43' do
|
179
|
+
# Reasoned S2, frame 1:43
|
180
|
+
# (run* q (fresh (x) (fresh (y) (== '( ,x ,y ,x) q)))) ;; => (_0 _1 _0)
|
181
|
+
|
182
|
+
result = run_star('q', fresh('x', fresh('y', equals(cons(x, cons(y, cons(x))), q))))
|
183
|
+
# q should be bound to '(,x ,y, ,x)
|
184
|
+
expect(result.car).to eq(cons(:_0, cons(:_1, cons(:_0))))
|
185
|
+
end
|
186
|
+
|
187
|
+
it "supports 'conj2' relation and passes frame 1:50" do
|
188
|
+
# Reasoned S2, frame 1:50
|
189
|
+
# (run* q (conj2 succeed succeed)) ;; => (_0)
|
190
|
+
|
191
|
+
result = run_star('q', conj2(succeed, succeed))
|
192
|
+
expect(result.car).to eq(:_0)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'passes frame 1:51' do
|
196
|
+
# Reasoned S2, frame 1:51
|
197
|
+
# (run* q (conj2 succeed (== 'corn q)) ;; => ('corn)
|
198
|
+
|
199
|
+
result = run_star('q', conj2(succeed, equals(:corn, q)))
|
200
|
+
expect(result.car).to eq(:corn)
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'passes frame 1:52' do
|
204
|
+
# Reasoned S2, frame 1:52
|
205
|
+
# (run* q (conj2 fail (== 'corn q)) ;; => ()
|
206
|
+
|
207
|
+
result = run_star('q', conj2(_fail, equals(:corn, q)))
|
208
|
+
expect(result).to be_null
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'passes frame 1:53' do
|
212
|
+
# Reasoned S2, frame 1:53
|
213
|
+
# (run* q (conj2 (== 'corn q)(== 'meal q)) ;; => ()
|
214
|
+
|
215
|
+
result = run_star('q', conj2(equals(:corn, q), equals(:meal, q)))
|
216
|
+
expect(result).to be_null
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'passes frame 1:54' do
|
220
|
+
# Reasoned S2, frame 1:54
|
221
|
+
# (run* q (conj2 (== 'corn q)(== 'corn q)) ;; => ('corn)
|
222
|
+
|
223
|
+
result = run_star('q', conj2(equals(:corn, q), equals(:corn, q)))
|
224
|
+
expect(result.car).to eq(:corn)
|
225
|
+
end
|
226
|
+
|
227
|
+
it "supports 'disj2' and passes frame 1:55" do
|
228
|
+
# Reasoned S2, frame 1:55
|
229
|
+
# (run* q (disj2 fail fail)) ;; => ()
|
230
|
+
|
231
|
+
result = run_star('q', disj2(_fail, _fail))
|
232
|
+
expect(result).to be_null
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'passes frame 1:56' do
|
236
|
+
# Reasoned S2, frame 1:56
|
237
|
+
# (run* q (disj2 (== 'olive q) fail)) ;; => ('olive)
|
238
|
+
|
239
|
+
result = run_star('q', disj2(equals(:olive, q), _fail))
|
240
|
+
expect(result.car).to eq(:olive)
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'passes frame 1:57' do
|
244
|
+
# Reasoned S2, frame 1:57
|
245
|
+
# (run* q (disj2 fail (== 'oil q))) ;; => (oil)
|
246
|
+
|
247
|
+
result = run_star('q', disj2(_fail, equals(:oil, q)))
|
248
|
+
expect(result.car).to eq(:oil)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'passes frame 1:58' do
|
252
|
+
# Reasoned S2, frame 1:58
|
253
|
+
# (run* q (disj2 (== 'olive q) (== 'oil q))) ;; => (olive oil)
|
254
|
+
|
255
|
+
result = run_star('q', disj2(equals(:olive, q), equals(:oil, q)))
|
256
|
+
expect(result.car).to eq(:olive)
|
257
|
+
expect(result.cdr.car).to eq(:oil)
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'passes frame 1:59' do
|
261
|
+
# Reasoned S2, frame 1:59
|
262
|
+
# (run* q (fresh (x) (fresh (y) (disj2 (== '( ,x ,y ) q) (== '( ,x ,y ) q)))))
|
263
|
+
# ;; => ((_0 _1) (_0 _1))
|
264
|
+
|
265
|
+
result = run_star('q', fresh('x', (fresh 'y', disj2(equals(cons(x, cons(y)), q), equals(cons(x, cons(y)), q)))))
|
266
|
+
# q should be bound to '(,x ,y), then to '(,y ,x)
|
267
|
+
expect(result.car).to eq(cons(:_0, cons(:_1)))
|
268
|
+
expect(result.cdr.car).to eq(cons(:_0, cons(:_1)))
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'passes frame 1:62' do
|
272
|
+
# Reasoned S2, frame 1:62
|
273
|
+
# (run* x (disj2
|
274
|
+
# (conj2 (== 'olive x) fail)
|
275
|
+
# (== 'oil x))) ;; => (oil)
|
276
|
+
|
277
|
+
result = run_star('x', disj2(conj2(equals(:olive, x), _fail), equals(:oil, x)))
|
278
|
+
expect(result.car).to eq(:oil)
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'passes frame 1:63' do
|
282
|
+
# Reasoned S2, frame 1:63
|
283
|
+
# (run* x (disj2
|
284
|
+
# (conj2 (== 'olive x) succeed)
|
285
|
+
# ('oil x))) ;; => (olive oil)
|
286
|
+
|
287
|
+
result = run_star('x', disj2(conj2(equals(:olive, x), succeed), equals(:oil, x)))
|
288
|
+
expect(result).to eq(cons(:olive, cons(:oil)))
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'passes frame 1:64' do
|
292
|
+
# Reasoned S2, frame 1:64
|
293
|
+
# (run* x (disj2
|
294
|
+
# (== 'oil x)
|
295
|
+
# (conj2 (== 'olive x) succeed))) ;; => (oil olive)
|
296
|
+
|
297
|
+
result = run_star('x', disj2(equals(:oil, x), conj2(equals(:olive, x), succeed)))
|
298
|
+
expect(result).to eq(cons(:oil, cons(:olive)))
|
299
|
+
end
|
300
|
+
|
301
|
+
it 'passes frame 1:65' do
|
302
|
+
# Reasoned S2, frame 1:65
|
303
|
+
# (run* x (disj2
|
304
|
+
# (conj2(== 'virgin x) fail)
|
305
|
+
# (disj2
|
306
|
+
# (== 'olive x)
|
307
|
+
# (dis2
|
308
|
+
# succeed
|
309
|
+
# (== 'oil x))))) ;; => (olive _0 oil)
|
310
|
+
|
311
|
+
result = run_star('x', disj2(conj2(equals(:virgin, x), _fail),
|
312
|
+
disj2(equals(:olive, x), disj2(succeed, equals(:oil, x)))))
|
313
|
+
expect(result).to eq(cons(:olive, cons(:_0, cons(:oil))))
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'passes frame 1:67' do
|
317
|
+
# Reasoned S2, frame 1:67
|
318
|
+
# (run* r
|
319
|
+
# (fresh x
|
320
|
+
# (fresh y
|
321
|
+
# (conj2
|
322
|
+
# (== 'split x)
|
323
|
+
# (conj2
|
324
|
+
# (== 'pea y)
|
325
|
+
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
326
|
+
|
327
|
+
result = run_star('r', fresh('x', fresh('y',
|
328
|
+
conj2(equals(:split, x),
|
329
|
+
conj2(equals(:pea, y), equals(cons(x, cons(y)), r))))))
|
330
|
+
expect(result).to eq(cons(cons(:split, cons(:pea))))
|
331
|
+
end
|
332
|
+
|
333
|
+
it 'passes frame 1:68' do
|
334
|
+
# Reasoned S2, frame 1:68
|
335
|
+
# (run* r
|
336
|
+
# (fresh x
|
337
|
+
# (fresh y
|
338
|
+
# (conj2
|
339
|
+
# (conj2
|
340
|
+
# (== 'split x)
|
341
|
+
# (== 'pea y)
|
342
|
+
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
343
|
+
|
344
|
+
result = run_star('r', fresh('x', fresh('y',
|
345
|
+
conj2(conj2(equals(:split, x), equals(:pea, y)),
|
346
|
+
equals(cons(x, cons(y)), r)))))
|
347
|
+
expect(result).to eq(cons(cons(:split, cons(:pea))))
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'passes frame 1:70' do
|
351
|
+
# Reasoned S2, frame 1:70
|
352
|
+
# (run* r
|
353
|
+
# (fresh (x y)
|
354
|
+
# (conj2
|
355
|
+
# (conj2
|
356
|
+
# (== 'split x)
|
357
|
+
# (== 'pea y)
|
358
|
+
# (== '(,x ,y) r))))) ;; => ((split pea))
|
359
|
+
|
360
|
+
result = run_star('r', fresh(%w[x y], conj2(
|
361
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
362
|
+
equals(cons(x, cons(y)), r))))
|
363
|
+
expect(result).to eq(cons(cons(:split, cons(:pea))))
|
364
|
+
end
|
365
|
+
|
366
|
+
it 'passes frame 1:72' do
|
367
|
+
# Reasoned S2, frame 1:72
|
368
|
+
# (run* (r x y)
|
369
|
+
# (conj2
|
370
|
+
# (conj2
|
371
|
+
# (== 'split x)
|
372
|
+
# (== 'pea y))
|
373
|
+
# (== '(,x ,y) r))) ;; => (((split pea) split pea))
|
374
|
+
# o
|
375
|
+
# / \
|
376
|
+
# o nil
|
377
|
+
# / \
|
378
|
+
# / \
|
379
|
+
# / \
|
380
|
+
# / \
|
381
|
+
# / \
|
382
|
+
# o o
|
383
|
+
# / \ / \
|
384
|
+
# split o split o
|
385
|
+
# / \ / \
|
386
|
+
# pea nil pea nil
|
387
|
+
|
388
|
+
result = run_star(%w[r x y], conj2(
|
389
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
390
|
+
equals(cons(x, cons(y)), r)))
|
391
|
+
expect(result.car.car.car).to eq(:split)
|
392
|
+
expect(result.car.car.cdr.car).to eq(:pea)
|
393
|
+
expect(result.car.car.cdr.cdr).to be_nil
|
394
|
+
expect(result.car.cdr.car).to eq(:split)
|
395
|
+
expect(result.car.cdr.cdr.car).to eq(:pea)
|
396
|
+
expect(result.car.cdr.cdr.cdr).to be_nil
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'passes frame 1:75' do
|
400
|
+
# Reasoned S2, frame 1:75
|
401
|
+
# (run* (x y)
|
402
|
+
# (conj2
|
403
|
+
# (== 'split x)
|
404
|
+
# (== 'pea y))) ;; => ((split pea))
|
405
|
+
|
406
|
+
result = run_star(%w[x y], conj2(equals(:split, x), equals(:pea, y)))
|
407
|
+
expect(result.car).to eq(list(:split, :pea))
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'passes frame 1:76' do
|
411
|
+
# Reasoned S2, frame 1:76
|
412
|
+
# (run* (x y)
|
413
|
+
# (disj2
|
414
|
+
# (conj2 (== 'split x) (== 'pea y))
|
415
|
+
# (conj2 (== 'red x) (== 'bean y)))) ;; => ((split pea)(red bean))
|
416
|
+
|
417
|
+
result = run_star(%w[x y], disj2(
|
418
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
419
|
+
conj2(equals(:red, x), equals(:bean, y))))
|
420
|
+
expect(result.car).to eq(list(:split, :pea))
|
421
|
+
expect(result.cdr.car).to eq(list(:red, :bean))
|
422
|
+
end
|
423
|
+
|
424
|
+
it 'passes frame 1:77' do
|
425
|
+
# Reasoned S2, frame 1:77
|
426
|
+
# (run* r
|
427
|
+
# (fresh (x y)
|
428
|
+
# (conj2
|
429
|
+
# (disj2
|
430
|
+
# (conj2 (== 'split x) (== 'pea y))
|
431
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
432
|
+
# (== '(,x ,y soup) r)))) ;; => ((split pea soup) (red bean soup))
|
433
|
+
|
434
|
+
result = run_star('r',
|
435
|
+
fresh(%w[x y], conj2(
|
436
|
+
disj2(
|
437
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
438
|
+
conj2(equals(:red, x), equals(:bean, y))),
|
439
|
+
equals(cons(x, cons(y, cons(:soup))), r))))
|
440
|
+
expect(result.car).to eq(list(:split, :pea, :soup))
|
441
|
+
expect(result.cdr.car).to eq(list(:red, :bean, :soup))
|
442
|
+
end
|
443
|
+
|
444
|
+
it 'passes frame 1:78' do
|
445
|
+
# Reasoned S2, frame 1:78
|
446
|
+
# (run* r
|
447
|
+
# (fresh (x y)
|
448
|
+
# (disj2
|
449
|
+
# (conj2 (== 'split x) (== 'pea y))
|
450
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
451
|
+
# (== '(,x ,y soup) r))) ;; => ((split pea soup) (red bean soup))
|
452
|
+
|
453
|
+
result = run_star('r',
|
454
|
+
fresh(%w[x y], [disj2(
|
455
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
456
|
+
conj2(equals(:red, x), equals(:bean, y))),
|
457
|
+
equals(cons(x, cons(y, cons(:soup))), r)]))
|
458
|
+
expect(result.car).to eq(list(:split, :pea, :soup))
|
459
|
+
expect(result.cdr.car).to eq(list(:red, :bean, :soup))
|
460
|
+
end
|
461
|
+
|
462
|
+
it 'passes frame 1:80' do
|
463
|
+
# Reasoned S2, frame 1:80
|
464
|
+
# (run* (x y z)
|
465
|
+
# (disj2
|
466
|
+
# (conj2 (== 'split x) (== 'pea y))
|
467
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
468
|
+
# (== 'soup z)) ;; => ((split pea soup) (red bean soup))
|
469
|
+
|
470
|
+
result = run_star(%w[x y z], [disj2(
|
471
|
+
conj2(equals(:split, x), equals(:pea, y)),
|
472
|
+
conj2(equals(:red, x), equals(:bean, y))),
|
473
|
+
equals(:soup, z)])
|
474
|
+
expect(result.car).to eq(list(:split, :pea, :soup))
|
475
|
+
expect(result.cdr.car).to eq(list(:red, :bean, :soup))
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'passes frame 1:81' do
|
479
|
+
# Reasoned S2, frame 1:81
|
480
|
+
# (run* (x y)
|
481
|
+
# (== 'split x)
|
482
|
+
# (== 'pea y)) ;; => ((split pea))
|
483
|
+
|
484
|
+
result = run_star(%w[x y], [equals(:split, x), equals(:pea, y)])
|
485
|
+
expect(result.car).to eq(list(:split, :pea))
|
486
|
+
end
|
487
|
+
|
488
|
+
it "supports 'defrel' and passes frame 1:82" do
|
489
|
+
# Reasoned S2, frame 1:82
|
490
|
+
# (defrel (teacupo t)
|
491
|
+
# (disj2 (== 'tea t) (== 'cup t)))
|
492
|
+
|
493
|
+
result = defrel('teacupo', 't') do
|
494
|
+
disj2(equals(:tea, t), equals(:cup, t))
|
495
|
+
end
|
496
|
+
|
497
|
+
expect(result).to be_kind_of(Core::DefRelation)
|
498
|
+
expect(result.name).to eq('teacupo')
|
499
|
+
expect(result.formals.size).to eq(1)
|
500
|
+
expect(result.formals[0].name).to eq('t')
|
501
|
+
g_template = result.goal_template
|
502
|
+
expect(g_template).to be_kind_of(Core::GoalTemplate)
|
503
|
+
expect(g_template.relation).to eq(Core::Disj2.instance)
|
504
|
+
|
505
|
+
first_arg = g_template.args[0]
|
506
|
+
expect(first_arg).to be_kind_of(Core::GoalTemplate)
|
507
|
+
expect(first_arg.relation).to eq(Core::Equals.instance)
|
508
|
+
expect(first_arg.args[0]).to eq(:tea)
|
509
|
+
expect(first_arg.args[1]).to be_kind_of(Core::FormalRef)
|
510
|
+
expect(first_arg.args[1].name).to eq('t')
|
511
|
+
second_arg = g_template.args[1]
|
512
|
+
expect(second_arg).to be_kind_of(Core::GoalTemplate)
|
513
|
+
expect(second_arg.relation).to eq(Core::Equals.instance)
|
514
|
+
expect(second_arg.args[0]).to eq(:cup)
|
515
|
+
expect(second_arg.args[1]).to be_kind_of(Core::FormalRef)
|
516
|
+
expect(second_arg.args[1].name).to eq('t')
|
517
|
+
end
|
518
|
+
|
519
|
+
def defrel_teacupo
|
520
|
+
defrel('teacupo', 't') { disj2(equals(:tea, t), equals(:cup, t)) }
|
521
|
+
end
|
522
|
+
|
523
|
+
it "supports the invokation of a 'defrel' and passes frame 1:83" do
|
524
|
+
# Reasoned S2, frame 1:83
|
525
|
+
# (run* x
|
526
|
+
# (teacupo x)) ;; => ((tea cup))
|
527
|
+
|
528
|
+
defrel_teacupo
|
529
|
+
result = run_star('x', teacupo(x))
|
530
|
+
|
531
|
+
expect(result).to eq(cons(:tea, cons(:cup)))
|
532
|
+
end
|
533
|
+
|
534
|
+
it 'supports booleans and passes frame 1:84' do
|
535
|
+
# Reasoned S2, frame 1:84
|
536
|
+
# (run* (x y)
|
537
|
+
# (disj2
|
538
|
+
# (conj2 (teacupo x) (== #t y))
|
539
|
+
# (conj2 (== #f x) (== #t y))) ;; => ((#f #t)(tea #t) (cup #t))
|
540
|
+
|
541
|
+
defrel_teacupo
|
542
|
+
result = run_star(%w[x y],
|
543
|
+
disj2(
|
544
|
+
conj2(teacupo(x), equals('#t', y)),
|
545
|
+
conj2(equals('#f', x), equals('#t', y))))
|
546
|
+
|
547
|
+
# Order of solutions differs from RS book
|
548
|
+
expect(result.car).to eq(cons(:tea, cons(true)))
|
549
|
+
expect(result.cdr.car).to eq(cons(:cup, cons(true)))
|
550
|
+
expect(result.cdr.cdr.car).to eq(cons(false, cons(true)))
|
551
|
+
end
|
552
|
+
|
553
|
+
it 'passes frame 1:85' do
|
554
|
+
# Reasoned S2, frame 1:85
|
555
|
+
# (run* (x y)
|
556
|
+
# (teacupo x)
|
557
|
+
# (teacupo y)) ;; => ((tea tea)(tea cup)(cup tea)(cup c))
|
558
|
+
|
559
|
+
defrel_teacupo
|
560
|
+
result = run_star(%w[x y], [teacupo(x), teacupo(y)])
|
561
|
+
|
562
|
+
expect(result.car).to eq(cons(:tea, cons(:tea)))
|
563
|
+
expect(result.cdr.car).to eq(cons(:tea, cons(:cup)))
|
564
|
+
expect(result.cdr.cdr.car).to eq(cons(:cup, cons(:tea)))
|
565
|
+
expect(result.cdr.cdr.cdr.car).to eq(cons(:cup, cons(:cup)))
|
566
|
+
end
|
567
|
+
|
568
|
+
it 'passes frame 1:86' do
|
569
|
+
# Reasoned S2, frame 1:86
|
570
|
+
# (run* (x y)
|
571
|
+
# (teacupo x)
|
572
|
+
# (teacupo x)) ;; => ((tea _0)(cup _0))
|
573
|
+
|
574
|
+
defrel_teacupo
|
575
|
+
result = run_star(%w[x y], [teacupo(x), teacupo(x)])
|
576
|
+
expect(result.to_s).to eq('((:tea _0) (:cup _0))')
|
577
|
+
end
|
578
|
+
|
579
|
+
it 'passes frame 1:87' do
|
580
|
+
# Reasoned S2, frame 1:87
|
581
|
+
# (run* (x y)
|
582
|
+
# (disj2
|
583
|
+
# (conj2 (teacupo x) (teacupo x))
|
584
|
+
# (conj2 (== #f x) (teacupo y)))) ;; => ((#f tea)(#f cup)(tea _0)(cup _0))
|
585
|
+
|
586
|
+
defrel_teacupo
|
587
|
+
result = run_star(%w[x y], disj2(
|
588
|
+
conj2(teacupo(x), teacupo(x)),
|
589
|
+
conj2(equals('#f', x), teacupo(y))))
|
590
|
+
|
591
|
+
# Order of solutions differs from RS book
|
592
|
+
expected = '((:tea _0) (:cup _0) (false :tea) (false :cup))'
|
593
|
+
expect(result.to_s).to eq(expected)
|
594
|
+
expect(result.car).to eq(cons(:tea, cons(:_0)))
|
595
|
+
expect(result.cdr.car).to eq(cons(:cup, cons(:_0)))
|
596
|
+
expect(result.cdr.cdr.car).to eq(cons(false, cons(:tea)))
|
597
|
+
expect(result.cdr.cdr.cdr.car).to eq(cons(false, cons(:cup)))
|
598
|
+
end
|
599
|
+
|
600
|
+
it 'supports conde and passes frame 1:88 (i)' do
|
601
|
+
# Reasoned S2, frame 1:88
|
602
|
+
# (run* (x y)
|
603
|
+
# (conde
|
604
|
+
# ((teacupo x) (teacupo x))
|
605
|
+
# ((== #f x) (teacupo y)))) ;; => ((#f tea)(#f cup)(tea _0)(cup _0))
|
606
|
+
|
607
|
+
defrel_teacupo
|
608
|
+
result = run_star(%w[x y], conde(
|
609
|
+
[teacupo(x), teacupo(x)],
|
610
|
+
[equals('#f', x), teacupo(y)]))
|
611
|
+
|
612
|
+
# Order of solutions differs from RS book
|
613
|
+
expected = '((:tea _0) (:cup _0) (false :tea) (false :cup))'
|
614
|
+
expect(result.to_s).to eq(expected)
|
615
|
+
end
|
616
|
+
|
617
|
+
it 'supports conde and passes frame 1:88 (ii)' do
|
618
|
+
# Reasoned S2, frame 1:88 (second part, a rewrite of 1:76)
|
619
|
+
# (run* (x y)
|
620
|
+
# (conde
|
621
|
+
# ((== 'split x) (== 'pea y))
|
622
|
+
# ((== 'red x) (== 'bean y)))) ;; => ((split pea)(red bean))
|
623
|
+
result = run_star(%w[x y], conde(
|
624
|
+
[equals(:split, x), equals(:pea, y)],
|
625
|
+
[equals(:red, x), equals(:bean, y)]))
|
626
|
+
|
627
|
+
expected = '((:split :pea) (:red :bean))'
|
628
|
+
expect(result.to_s).to eq(expected)
|
629
|
+
end
|
630
|
+
|
631
|
+
it 'passes frame 1:89' do
|
632
|
+
# Reasoned S2, frame 1:89 (rewrite of 1:62)
|
633
|
+
# (run* x
|
634
|
+
# (conde
|
635
|
+
# ((== 'olive x) fail)
|
636
|
+
# ('oil x))) ;; => (oil)
|
637
|
+
|
638
|
+
result = run_star('x', conde(
|
639
|
+
[equals(:olive, x), _fail],
|
640
|
+
equals(:oil, x)))
|
641
|
+
|
642
|
+
expect(result.to_s).to eq('(:oil)')
|
643
|
+
end
|
644
|
+
|
645
|
+
it 'passes frame 1:90' do
|
646
|
+
# Reasoned S2, frame 1:90
|
647
|
+
# (run* (x y)
|
648
|
+
# (conde
|
649
|
+
# ((fresh (z)
|
650
|
+
# (== 'lentil z)))
|
651
|
+
# ((== x y)))) ;; => ((_0 _1)(_0 _0))
|
652
|
+
|
653
|
+
result = run_star(%w[x y], conde(
|
654
|
+
[fresh(%w[z], equals(:lentil, z))],
|
655
|
+
[equals(x, y)]))
|
656
|
+
|
657
|
+
expect(result.to_s).to eq('((_0 _1) (_0 _0))')
|
658
|
+
end
|
659
|
+
|
660
|
+
it 'passes frame 1:91' do
|
661
|
+
# Reasoned S2, frame 1:91
|
662
|
+
# (run* (x y)
|
663
|
+
# (conde
|
664
|
+
# ((== 'split x) (== 'pea y))
|
665
|
+
# ((== 'red x) (== 'bean y))
|
666
|
+
# ((== 'green x) (== 'lentil y))))
|
667
|
+
# ;; => ((split pea)(red bean)(green lentil))
|
668
|
+
result = run_star(%w[x y], conde(
|
669
|
+
[equals(:split, x), equals(:pea, y)],
|
670
|
+
[equals(:red, x), equals(:bean, y)],
|
671
|
+
[equals(:green, x), equals(:lentil, y)]))
|
672
|
+
|
673
|
+
expected = '((:split :pea) (:red :bean) (:green :lentil))'
|
674
|
+
expect(result.to_s).to eq(expected)
|
675
|
+
end
|
676
|
+
end # context
|
677
|
+
end # describe
|
678
|
+
end # module
|
679
|
+
end # module
|