mini_kraken 0.2.03 → 0.3.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 +378 -333
- data/CHANGELOG.md +48 -0
- data/README.md +29 -21
- data/lib/mini_kraken/atomic/all_atomic.rb +5 -0
- data/lib/mini_kraken/atomic/atomic_term.rb +96 -0
- data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
- data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -5
- data/lib/mini_kraken/atomic/k_string.rb +17 -0
- data/lib/mini_kraken/{core → atomic}/k_symbol.rb +4 -8
- data/lib/mini_kraken/composite/all_composite.rb +4 -0
- data/lib/mini_kraken/composite/composite_term.rb +27 -0
- data/lib/mini_kraken/composite/cons_cell.rb +301 -0
- data/lib/mini_kraken/composite/cons_cell_visitor.rb +50 -0
- data/lib/mini_kraken/composite/list.rb +32 -0
- data/lib/mini_kraken/core/all_core.rb +8 -0
- data/lib/mini_kraken/core/any_value.rb +31 -7
- data/lib/mini_kraken/core/arity.rb +69 -0
- data/lib/mini_kraken/core/association.rb +29 -4
- data/lib/mini_kraken/core/association_copy.rb +50 -0
- data/lib/mini_kraken/core/base_term.rb +13 -0
- data/lib/mini_kraken/core/blackboard.rb +315 -0
- data/lib/mini_kraken/core/bookmark.rb +46 -0
- data/lib/mini_kraken/core/context.rb +492 -0
- data/lib/mini_kraken/core/duck_fiber.rb +21 -19
- data/lib/mini_kraken/core/entry.rb +40 -0
- data/lib/mini_kraken/core/fail.rb +20 -18
- data/lib/mini_kraken/core/fusion.rb +29 -0
- data/lib/mini_kraken/core/goal.rb +20 -29
- data/lib/mini_kraken/core/log_var.rb +22 -0
- data/lib/mini_kraken/core/log_var_ref.rb +108 -0
- data/lib/mini_kraken/core/nullary_relation.rb +2 -9
- data/lib/mini_kraken/core/parametrized_term.rb +68 -0
- data/lib/mini_kraken/core/relation.rb +14 -28
- data/lib/mini_kraken/core/scope.rb +67 -0
- data/lib/mini_kraken/core/solver_adapter.rb +58 -0
- data/lib/mini_kraken/core/specification.rb +48 -0
- data/lib/mini_kraken/core/succeed.rb +21 -17
- data/lib/mini_kraken/core/symbol_table.rb +137 -0
- data/lib/mini_kraken/core/term.rb +15 -4
- data/lib/mini_kraken/glue/dsl.rb +44 -88
- data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
- data/lib/mini_kraken/rela/all_rela.rb +8 -0
- data/lib/mini_kraken/rela/binary_relation.rb +30 -0
- data/lib/mini_kraken/rela/conde.rb +143 -0
- data/lib/mini_kraken/rela/conj2.rb +65 -0
- data/lib/mini_kraken/rela/def_relation.rb +93 -0
- data/lib/mini_kraken/rela/disj2.rb +70 -0
- data/lib/mini_kraken/rela/fresh.rb +98 -0
- data/lib/mini_kraken/{core → rela}/goal_relation.rb +7 -9
- data/lib/mini_kraken/rela/unify.rb +265 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/mini_kraken.gemspec +2 -2
- data/spec/.rubocop.yml +1 -1
- data/spec/atomic/atomic_term_spec.rb +98 -0
- data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
- data/spec/{core → atomic}/k_symbol_spec.rb +3 -16
- data/spec/composite/cons_cell_spec.rb +225 -0
- data/spec/{core → composite}/cons_cell_visitor_spec.rb +36 -20
- data/spec/composite/list_spec.rb +50 -0
- data/spec/core/any_value_spec.rb +52 -0
- data/spec/core/arity_spec.rb +92 -0
- data/spec/core/association_copy_spec.rb +69 -0
- data/spec/core/association_spec.rb +31 -4
- data/spec/core/blackboard_spec.rb +287 -0
- data/spec/core/bookmark_spec.rb +40 -0
- data/spec/core/context_spec.rb +245 -0
- data/spec/core/core_spec.rb +40 -0
- data/spec/core/duck_fiber_spec.rb +16 -46
- data/spec/core/fail_spec.rb +5 -6
- data/spec/core/goal_spec.rb +22 -12
- data/spec/core/log_var_ref_spec.rb +105 -0
- data/spec/core/log_var_spec.rb +64 -0
- data/spec/core/nullary_relation_spec.rb +33 -0
- data/spec/core/parametrized_tem_spec.rb +39 -0
- data/spec/core/relation_spec.rb +33 -0
- data/spec/core/scope_spec.rb +73 -0
- data/spec/core/solver_adapter_spec.rb +70 -0
- data/spec/core/specification_spec.rb +43 -0
- data/spec/core/succeed_spec.rb +5 -5
- data/spec/core/symbol_table_spec.rb +142 -0
- data/spec/glue/dsl_chap1_spec.rb +88 -144
- data/spec/glue/dsl_chap2_spec.rb +454 -19
- data/spec/glue/run_star_expression_spec.rb +81 -906
- data/spec/rela/conde_spec.rb +153 -0
- data/spec/rela/conj2_spec.rb +123 -0
- data/spec/rela/def_relation_spec.rb +119 -0
- data/spec/rela/disj2_spec.rb +117 -0
- data/spec/rela/fresh_spec.rb +147 -0
- data/spec/rela/unify_spec.rb +369 -0
- data/spec/support/factory_atomic.rb +29 -0
- data/spec/support/factory_composite.rb +21 -0
- data/spec/support/factory_methods.rb +11 -26
- metadata +98 -70
- data/lib/mini_kraken/core/association_walker.rb +0 -183
- data/lib/mini_kraken/core/atomic_term.rb +0 -67
- data/lib/mini_kraken/core/base_arg.rb +0 -10
- data/lib/mini_kraken/core/binary_relation.rb +0 -63
- data/lib/mini_kraken/core/composite_goal.rb +0 -46
- data/lib/mini_kraken/core/composite_term.rb +0 -41
- data/lib/mini_kraken/core/conde.rb +0 -143
- data/lib/mini_kraken/core/conj2.rb +0 -79
- data/lib/mini_kraken/core/cons_cell.rb +0 -82
- data/lib/mini_kraken/core/cons_cell_visitor.rb +0 -102
- data/lib/mini_kraken/core/def_relation.rb +0 -53
- data/lib/mini_kraken/core/designation.rb +0 -55
- data/lib/mini_kraken/core/disj2.rb +0 -72
- data/lib/mini_kraken/core/environment.rb +0 -73
- data/lib/mini_kraken/core/equals.rb +0 -193
- data/lib/mini_kraken/core/formal_arg.rb +0 -22
- data/lib/mini_kraken/core/formal_ref.rb +0 -25
- data/lib/mini_kraken/core/freshness.rb +0 -45
- data/lib/mini_kraken/core/goal_arg.rb +0 -12
- data/lib/mini_kraken/core/goal_template.rb +0 -102
- data/lib/mini_kraken/core/k_boolean.rb +0 -35
- data/lib/mini_kraken/core/outcome.rb +0 -63
- data/lib/mini_kraken/core/variable.rb +0 -41
- data/lib/mini_kraken/core/variable_ref.rb +0 -84
- data/lib/mini_kraken/core/vocabulary.rb +0 -446
- data/lib/mini_kraken/glue/fresh_env.rb +0 -103
- data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
- data/spec/core/association_walker_spec.rb +0 -192
- data/spec/core/conde_spec.rb +0 -147
- data/spec/core/conj2_spec.rb +0 -114
- data/spec/core/cons_cell_spec.rb +0 -107
- data/spec/core/def_relation_spec.rb +0 -97
- data/spec/core/disj2_spec.rb +0 -99
- data/spec/core/environment_spec.rb +0 -142
- data/spec/core/equals_spec.rb +0 -317
- data/spec/core/goal_template_spec.rb +0 -74
- data/spec/core/outcome_spec.rb +0 -56
- data/spec/core/variable_ref_spec.rb +0 -30
- data/spec/core/variable_spec.rb +0 -35
- data/spec/core/vocabulary_spec.rb +0 -219
- data/spec/glue/fresh_env_factory_spec.rb +0 -97
- data/spec/glue/fresh_env_spec.rb +0 -62
@@ -1,19 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
-
|
5
|
-
require_relative '../../lib/mini_kraken/core/
|
6
|
-
require_relative '../../lib/mini_kraken/
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '../../lib/mini_kraken/core/equals'
|
10
|
-
require_relative '../../lib/mini_kraken/core/fail'
|
11
|
-
require_relative '../../lib/mini_kraken/core/formal_arg'
|
12
|
-
require_relative '../../lib/mini_kraken/core/formal_ref'
|
13
|
-
require_relative '../../lib/mini_kraken/core/goal_template'
|
14
|
-
require_relative '../../lib/mini_kraken/core/succeed'
|
15
|
-
|
16
|
-
require_relative '../support/factory_methods'
|
4
|
+
|
5
|
+
require_relative '../../lib/mini_kraken/core/all_core'
|
6
|
+
require_relative '../../lib/mini_kraken/rela/all_rela'
|
7
|
+
require_relative '../support/factory_atomic'
|
8
|
+
# require_relative '../support/factory_methods'
|
17
9
|
|
18
10
|
# Load the class under test
|
19
11
|
require_relative '../../lib/mini_kraken/glue/run_star_expression'
|
@@ -22,15 +14,19 @@ require_relative '../../lib/mini_kraken/glue/run_star_expression'
|
|
22
14
|
module MiniKraken
|
23
15
|
module Glue
|
24
16
|
describe RunStarExpression do
|
25
|
-
include
|
17
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
26
18
|
|
27
19
|
let(:pea) { k_symbol(:pea) }
|
28
20
|
let(:pod) { k_symbol(:pod) }
|
29
|
-
let(:sample_goal) {
|
21
|
+
let(:sample_goal) { unify_goal(pea, pod) }
|
30
22
|
let(:fails) { Core::Goal.new(Core::Fail.instance, []) }
|
31
23
|
let(:succeeds) { Core::Goal.new(Core::Succeed.instance, []) }
|
32
24
|
subject { RunStarExpression.new('q', sample_goal) }
|
33
25
|
|
26
|
+
def unify_goal(arg1, arg2)
|
27
|
+
Core::Goal.new(Rela::Unify.instance, [arg1, arg2])
|
28
|
+
end
|
29
|
+
|
34
30
|
context 'Initialization:' do
|
35
31
|
it 'could be initialized with a name and a goal' do
|
36
32
|
expect { RunStarExpression.new('q', sample_goal) }.not_to raise_error
|
@@ -40,17 +36,18 @@ module MiniKraken
|
|
40
36
|
expect { RunStarExpression.new(%w[r x y], sample_goal) }.not_to raise_error
|
41
37
|
end
|
42
38
|
|
43
|
-
it 'could be initialized with multiple names and goals' do
|
44
|
-
expect { RunStarExpression.new(%w[r x y], [succeeds, succeeds]) }.not_to raise_error
|
45
|
-
end
|
39
|
+
# it 'could be initialized with multiple names and goals' do
|
40
|
+
# expect { RunStarExpression.new(%w[r x y], [succeeds, succeeds]) }.not_to raise_error
|
41
|
+
# end
|
46
42
|
|
47
43
|
it 'should know its variables' do
|
48
|
-
|
49
|
-
expect(
|
44
|
+
definitions = subject.ctx.symbol_table.current_scope.defns
|
45
|
+
expect(definitions['q']).not_to be_nil
|
46
|
+
expect(definitions.values[0].name).to eq('q')
|
50
47
|
end
|
51
48
|
|
52
49
|
it 'should know its goal' do
|
53
|
-
expect(subject.
|
50
|
+
expect(subject.goal).to eq(sample_goal)
|
54
51
|
end
|
55
52
|
end # context
|
56
53
|
|
@@ -70,25 +67,37 @@ module MiniKraken
|
|
70
67
|
let(:split) { k_symbol(:split) }
|
71
68
|
let(:tea) { k_symbol(:tea) }
|
72
69
|
let(:virgin) { k_symbol(:virgin) }
|
73
|
-
let(:ref_q) { Core::
|
74
|
-
let(:ref_r) { Core::
|
75
|
-
let(:ref_x) { Core::
|
76
|
-
let(:ref_y) { Core::
|
77
|
-
let(:ref_z) { Core::
|
78
|
-
let(:ref_s) { Core::
|
79
|
-
let(:ref_t) { Core::
|
80
|
-
let(:ref_u) { Core::
|
81
|
-
let(:ref_z) { Core::
|
70
|
+
let(:ref_q) { Core::LogVarRef.new('q') }
|
71
|
+
let(:ref_r) { Core::LogVarRef.new('r') }
|
72
|
+
let(:ref_x) { Core::LogVarRef.new('x') }
|
73
|
+
let(:ref_y) { Core::LogVarRef.new('y') }
|
74
|
+
let(:ref_z) { Core::LogVarRef.new('z') }
|
75
|
+
let(:ref_s) { Core::LogVarRef.new('s') }
|
76
|
+
let(:ref_t) { Core::LogVarRef.new('t') }
|
77
|
+
let(:ref_u) { Core::LogVarRef.new('u') }
|
78
|
+
let(:ref_z) { Core::LogVarRef.new('z') }
|
82
79
|
let(:t_ref) { Core::FormalRef.new('t') }
|
83
|
-
let(:equals_tea) { Core::GoalTemplate.new(Core::Equals.instance, [tea, t_ref]) }
|
84
|
-
let(:equals_cup) { Core::GoalTemplate.new(Core::Equals.instance, [cup, t_ref]) }
|
85
|
-
let(:g_template) { Core::GoalTemplate.new(Core::Disj2.instance, [equals_tea, equals_cup]) }
|
86
|
-
let(:formal_t) { Core::FormalArg.new('t') }
|
87
80
|
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
81
|
+
# @return [Core::Goal]
|
82
|
+
def fresh(names, subgoal)
|
83
|
+
# puts "#{__callee__} #{names}"
|
84
|
+
if names.kind_of?(Array)
|
85
|
+
k_names = names.map { |nm| Atomic::KString.new(nm) }
|
86
|
+
else
|
87
|
+
k_names = Atomic::KString.new(names)
|
88
|
+
end
|
89
|
+
Core::Goal.new(Rela::Fresh.instance, [k_names, subgoal])
|
90
|
+
end
|
91
|
+
|
92
|
+
def conj2(term1, term2)
|
93
|
+
Core::Goal.new(Rela::Conj2.instance, [term1, term2])
|
94
|
+
end
|
95
|
+
|
96
|
+
def unify(term1, term2)
|
97
|
+
Core::Goal.new(Rela::Unify.instance, [term1, term2])
|
98
|
+
end
|
99
|
+
|
100
|
+
|
92
101
|
|
93
102
|
it 'should return a null list with the fail goal' do
|
94
103
|
# Reasoned S2, frame 1:7
|
@@ -99,904 +108,70 @@ module MiniKraken
|
|
99
108
|
expect(instance.run).to be_null
|
100
109
|
end
|
101
110
|
|
102
|
-
it 'should return a null list
|
111
|
+
it 'should return a null list with a failing goal' do
|
103
112
|
# Reasoned S2, frame 1:10
|
104
|
-
# (run* q (== 'pea 'pod) ;; => ()
|
105
|
-
|
106
|
-
expect(subject.run).to be_null
|
107
|
-
expect(ref_q.fresh?(subject.env)).to be_truthy
|
108
|
-
end
|
109
|
-
|
110
|
-
it 'should unify the variable with the equals goal with symbol' do
|
111
|
-
goal = equals_goal(ref_q, pea)
|
112
|
-
instance = RunStarExpression.new('q', goal)
|
113
|
+
# (run* q (== 'pea 'pod)) ;; => ()
|
114
|
+
instance = RunStarExpression.new('q', unify(pea, pod))
|
113
115
|
|
114
|
-
|
115
|
-
# (run* q (== q 'pea) ;; => (pea)
|
116
|
-
expect(instance.run.car).to eq(pea)
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'should unify the righthand variable(s)' do
|
120
|
-
goal = equals_goal(pea, ref_q)
|
121
|
-
instance = RunStarExpression.new('q', goal)
|
122
|
-
|
123
|
-
# Reasoned S2, frame 1:12
|
124
|
-
# (run* q (== 'pea q) ;; => (pea)
|
125
|
-
expect(instance.run.car).to eq(pea)
|
116
|
+
expect(instance.run).to be_null
|
126
117
|
end
|
127
118
|
|
128
|
-
it 'should return a
|
129
|
-
instance = RunStarExpression.new('q', succeeds)
|
130
|
-
expect(instance.env.vars).to be_include('q')
|
131
|
-
|
132
|
-
# (display (run* q succeed)) ;; => (_0)
|
133
|
-
# Reasoned S2, frame 1:16
|
134
|
-
result = instance.run
|
135
|
-
|
119
|
+
it 'should return a _0 with the succeed goal' do
|
136
120
|
# Reasoned S2, frame 1:17
|
137
|
-
|
138
|
-
|
121
|
+
# (run* q #s) ;; => (_0)
|
122
|
+
success = Core::Goal.new(Core::Succeed.instance, [])
|
123
|
+
instance = RunStarExpression.new('q', success)
|
139
124
|
|
140
|
-
|
141
|
-
goal = equals_goal(pea, pea)
|
142
|
-
instance = RunStarExpression.new('q', goal)
|
143
|
-
|
144
|
-
# (display (run* q (== 'pea 'pea))) ;; => (_0)
|
145
|
-
# Reasoned S2, frame 1:19
|
146
|
-
result = instance.run
|
147
|
-
expect(result.car).to eq(any_value(0))
|
148
|
-
end
|
149
|
-
|
150
|
-
it 'should keep variable fresh when no unification occurs (II)' do
|
151
|
-
ref1_q = Core::VariableRef.new('q')
|
152
|
-
ref2_q = Core::VariableRef.new('q')
|
153
|
-
goal = equals_goal(ref1_q, ref2_q)
|
154
|
-
instance = RunStarExpression.new('q', goal)
|
155
|
-
|
156
|
-
# (display (run* q (== q q))) ;; => (_0)
|
157
|
-
# Reasoned S2, frame 1:20
|
158
|
-
result = instance.run
|
159
|
-
expect(result.car).to eq(any_value(0))
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'should accept the nesting of sub-environment' do
|
163
|
-
goal = equals_goal(pea, ref_q)
|
164
|
-
fresh_env = FreshEnv.new(['x'], goal)
|
165
|
-
instance = RunStarExpression.new('q', fresh_env)
|
166
|
-
|
167
|
-
# Reasoned S2, frame 1:21..23
|
168
|
-
# (run* q (fresh (x) (== 'pea q))) ;; => (pea)
|
169
|
-
result = instance.run
|
170
|
-
|
171
|
-
# Reasoned S2, frame 1:40
|
172
|
-
expect(ref_q.different_from?(ref_x, fresh_env)).to be_truthy
|
173
|
-
expect(result.car).to eq(pea)
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'should unify nested variables' do
|
177
|
-
goal = equals_goal(pea, ref_x)
|
178
|
-
fresh_env = FreshEnv.new(['x'], goal)
|
179
|
-
instance = RunStarExpression.new('q', fresh_env)
|
180
|
-
|
181
|
-
# Reasoned S2, frame 1:24
|
182
|
-
# (run* q (fresh (x) (== 'pea x))) ;; => (_0)
|
183
|
-
result = instance.run
|
184
|
-
expect(result.car).to eq(any_value(0))
|
185
|
-
end
|
186
|
-
|
187
|
-
it 'should accept expression with variables' do
|
188
|
-
goal = equals_goal(cons(ref_x), ref_q)
|
189
|
-
fresh_env = FreshEnv.new(['x'], goal)
|
190
|
-
instance = RunStarExpression.new('q', fresh_env)
|
191
|
-
|
192
|
-
# Reasoned S2, frame 1:25
|
193
|
-
# (run* q (fresh (x) (== (cons x '()) q))) ;; => ((_0))
|
194
|
-
result = instance.run
|
195
|
-
expect(result.car).to eq(cons(any_value(0)))
|
196
|
-
end
|
197
|
-
|
198
|
-
it 'should accept fused variables' do
|
199
|
-
goal = equals_goal(ref_x, ref_q)
|
200
|
-
fresh_env = FreshEnv.new(['x'], goal)
|
201
|
-
instance = RunStarExpression.new('q', fresh_env)
|
202
|
-
|
203
|
-
# Reasoned S2, frame 1:31
|
204
|
-
# (run* q (fresh (x) (== x q))) ;; => (_0)
|
205
|
-
result = instance.run
|
206
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
207
|
-
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
208
|
-
|
209
|
-
# q should be fused with x...
|
210
|
-
expect(ref_q.fused_with?(ref_x, fresh_env)).to be_truthy
|
211
|
-
expect(ref_q.names_fused(fresh_env)).to eq(['x'])
|
212
|
-
expect(ref_x.names_fused(fresh_env)).to eq(['q'])
|
213
|
-
expect(result.car).to eq(any_value(0))
|
214
|
-
end
|
215
|
-
|
216
|
-
it 'should cope with complex equality expressions' do
|
217
|
-
expr1 = cons(cons(cons(pea)), pod)
|
218
|
-
expr2 = cons(cons(cons(pea)), pod)
|
219
|
-
goal = equals_goal(expr1, expr2)
|
220
|
-
instance = RunStarExpression.new('q', goal)
|
221
|
-
|
222
|
-
# Reasoned S2, frame 1:32
|
223
|
-
# (run* q (== '(((pea)) pod) '(((pea)) pod))) ;; => (_0)
|
224
|
-
result = instance.run
|
225
|
-
expect(result.car).to eq(any_value(0))
|
125
|
+
expect(instance.run.to_s).to eq('(_0)')
|
226
126
|
end
|
227
127
|
|
228
|
-
it 'should
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
instance = RunStarExpression.new('q', goal)
|
233
|
-
|
234
|
-
# Beware: quasiquoting
|
235
|
-
# Reasoned S2, frame 1:33
|
236
|
-
# (run* q (== '(((pea)) pod) `(((pea)) ,q))) ;; => ('pod)
|
237
|
-
result = instance.run
|
238
|
-
expect(result.car).to eq(pod)
|
239
|
-
end
|
240
|
-
|
241
|
-
it 'should unify complex equality expressions (II)' do
|
242
|
-
expr1 = cons(cons(cons(ref_q)), pod)
|
243
|
-
expr2 = cons(cons(cons(pea)), pod)
|
244
|
-
goal = equals_goal(expr1, expr2)
|
245
|
-
instance = RunStarExpression.new('q', goal)
|
246
|
-
|
247
|
-
# Reasoned S2, frame 1:34
|
248
|
-
# (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pea)
|
249
|
-
result = instance.run
|
250
|
-
expect(result.car).to eq(pea)
|
251
|
-
end
|
252
|
-
|
253
|
-
it 'should unify complex equality expressions (III)' do
|
254
|
-
expr1 = cons(cons(cons(ref_q)), pod)
|
255
|
-
expr2 = cons(cons(cons(ref_x)), pod)
|
256
|
-
goal = equals_goal(expr1, expr2)
|
257
|
-
fresh_env = FreshEnv.new(['x'], goal)
|
258
|
-
instance = RunStarExpression.new('q', fresh_env)
|
259
|
-
|
260
|
-
# Reasoned S2, frame 1:35
|
261
|
-
# (run* q (fresh (x) (== '(((,q)) pod) `(((,x)) pod)))) ;; => (_0)
|
262
|
-
result = instance.run
|
263
|
-
expect(result.car).to eq(any_value(0))
|
264
|
-
end
|
265
|
-
|
266
|
-
it 'should unify complex equality expressions (IV)' do
|
267
|
-
# Reasoned S2, frame 1:36
|
268
|
-
# (run* q (fresh (x) (== '(((,q)) (,x)) `(((,x)) pod)))) ;; => ('pod)
|
269
|
-
expr1 = cons(cons(cons(ref_q)), cons(ref_x))
|
270
|
-
expr2 = cons(cons(cons(ref_x)), cons(pod))
|
271
|
-
goal = equals_goal(expr1, expr2)
|
272
|
-
fresh_env = FreshEnv.new(['x'], goal)
|
273
|
-
instance = RunStarExpression.new('q', fresh_env)
|
274
|
-
|
275
|
-
result = instance.run
|
276
|
-
expect(result.car).to eq(pod)
|
277
|
-
end
|
278
|
-
|
279
|
-
it 'should unify with repeated fresh variable' do
|
280
|
-
# Reasoned S2, frame 1:37
|
281
|
-
# (run* q (fresh (x) (== '( ,x ,x) q))) ;; => (_0 _0)
|
282
|
-
expr1 = cons(ref_x, cons(ref_x))
|
283
|
-
goal = equals_goal(expr1, ref_q)
|
284
|
-
fresh_env = FreshEnv.new(['x'], goal)
|
285
|
-
instance = RunStarExpression.new('q', fresh_env)
|
286
|
-
|
287
|
-
result = instance.run
|
288
|
-
expect(result.car).to eq(cons(any_value(0), cons(any_value(0))))
|
289
|
-
end
|
290
|
-
|
291
|
-
it 'should unify multiple times' do
|
292
|
-
# Reasoned S2, frame 1:38
|
293
|
-
# (run* q (fresh (x) (fresh (y) (== '( ,q ,y) '((,x ,y) ,x))))) ;; => (_0 _0)
|
294
|
-
expr1 = cons(ref_q, cons(ref_y))
|
295
|
-
expr2 = cons(cons(ref_x, cons(ref_y)), cons(ref_x))
|
296
|
-
goal = equals_goal(expr1, expr2)
|
297
|
-
fresh_env_y = FreshEnv.new(['y'], goal)
|
298
|
-
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
299
|
-
instance = RunStarExpression.new('q', fresh_env_x)
|
300
|
-
|
301
|
-
result = instance.run
|
302
|
-
|
303
|
-
# y should be fused with x...
|
304
|
-
var_x = fresh_env_y.name2var('x')
|
305
|
-
var_y = fresh_env_y.name2var('y')
|
306
|
-
expect(var_x.i_name).to eq(var_y.i_name)
|
307
|
-
expect(ref_y.fused_with?(ref_x, fresh_env_y)).to be_truthy
|
308
|
-
expect(ref_x.names_fused(fresh_env_y)).to eq(['y'])
|
309
|
-
expect(ref_y.names_fused(fresh_env_y)).to eq(['x'])
|
310
|
-
|
311
|
-
# q should be bound to '(,x ,x)
|
312
|
-
expect(result.car).to eq(cons(any_value(0), cons(any_value(0))))
|
313
|
-
end
|
314
|
-
|
315
|
-
it 'should support multiple fresh variables' do
|
316
|
-
# Reasoned S2, frame 1:41
|
317
|
-
# (run* q (fresh (x) (fresh (y) (== '( ,x ,y) q)))) ;; => (_0 _1)
|
318
|
-
expr1 = cons(ref_x, cons(ref_y))
|
319
|
-
goal = equals_goal(expr1, ref_q)
|
320
|
-
fresh_env_y = FreshEnv.new(['y'], goal)
|
321
|
-
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
322
|
-
instance = RunStarExpression.new('q', fresh_env_x)
|
128
|
+
it 'should return a value with a succeeding goal and q bound' do
|
129
|
+
# Reasoned S2, frame 1:11
|
130
|
+
# (run* q (== q 'pea)) ;; => (pea)
|
131
|
+
instance = RunStarExpression.new('q', unify(ref_q, pea))
|
323
132
|
|
324
|
-
|
325
|
-
# q should be bound to '(,x ,y)
|
326
|
-
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
133
|
+
expect(instance.run.to_s).to eq('(:pea)')
|
327
134
|
end
|
328
135
|
|
329
|
-
it 'should
|
330
|
-
# Reasoned S2, frame 1:
|
331
|
-
# (run*
|
332
|
-
|
333
|
-
goal = equals_goal(expr1, ref_s)
|
334
|
-
fresh_env_u = FreshEnv.new(['u'], goal)
|
335
|
-
fresh_env_t = FreshEnv.new(['t'], fresh_env_u)
|
336
|
-
instance = RunStarExpression.new('s', fresh_env_t)
|
136
|
+
it 'should return a _0 with a succeeding goal and q fresh' do
|
137
|
+
# Reasoned S2, frame 1:11
|
138
|
+
# (run* q (== q q)) ;; => (_0)
|
139
|
+
instance = RunStarExpression.new('q', unify(ref_q, ref_q))
|
337
140
|
|
338
|
-
|
339
|
-
# s should be bound to '(,t ,u)
|
340
|
-
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
141
|
+
expect(instance.run.to_s).to eq('(_0)')
|
341
142
|
end
|
342
143
|
|
343
|
-
it 'should support
|
344
|
-
# Reasoned S2, frame 1:
|
345
|
-
# (run* q (fresh (x) (
|
346
|
-
|
347
|
-
|
348
|
-
fresh_env_y = FreshEnv.new(['y'], goal)
|
349
|
-
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
350
|
-
instance = RunStarExpression.new('q', fresh_env_x)
|
144
|
+
it 'should support the fresh form to nest scopes' do
|
145
|
+
# Reasoned S2, frame 1:21
|
146
|
+
# (run* q (fresh (x) (== 'pea q))) ;; => (pea)
|
147
|
+
subgoal = unify(pea, ref_q)
|
148
|
+
instance = RunStarExpression.new('q', fresh('x', subgoal))
|
351
149
|
|
352
|
-
|
353
|
-
# q should be bound to '(,x ,y, ,x)
|
354
|
-
expect(result.car).to eq(cons(any_value(0), cons(any_value(1), cons(any_value(0)))))
|
150
|
+
expect(instance.run.to_s).to eq('(:pea)')
|
355
151
|
end
|
356
152
|
|
357
153
|
it 'should support conjunction of two succeed' do
|
358
|
-
goal = conj2_goal(succeeds, succeeds)
|
359
|
-
instance = RunStarExpression.new('q', goal)
|
360
|
-
|
361
154
|
# Reasoned S2, frame 1:50
|
362
155
|
# (run* q (conj2 succeed succeed)) ;; => (_0)
|
156
|
+
goal = conj2(succeeds, succeeds)
|
157
|
+
instance = RunStarExpression.new('q', goal)
|
158
|
+
|
363
159
|
result = instance.run
|
364
|
-
expect(result.
|
160
|
+
expect(result.to_s).to eq('(_0)')
|
365
161
|
end
|
366
162
|
|
367
163
|
it 'should support conjunction of one succeed and a successful goal' do
|
368
|
-
subgoal = equals_goal(corn, ref_q)
|
369
|
-
goal = conj2_goal(succeeds, subgoal)
|
370
|
-
instance = RunStarExpression.new('q', goal)
|
371
|
-
|
372
164
|
# Reasoned S2, frame 1:51
|
373
165
|
# (run* q (conj2 succeed (== 'corn q)) ;; => ('corn)
|
374
|
-
|
375
|
-
|
376
|
-
end
|
377
|
-
|
378
|
-
it 'should support conjunction of one fail and a successful goal' do
|
379
|
-
subgoal = equals_goal(corn, ref_q)
|
380
|
-
goal = conj2_goal(fails, subgoal)
|
381
|
-
instance = RunStarExpression.new('q', goal)
|
382
|
-
|
383
|
-
# Reasoned S2, frame 1:52
|
384
|
-
# (run* q (conj2 fail (== 'corn q)) ;; => ()
|
385
|
-
expect(instance.run).to be_null
|
386
|
-
end
|
387
|
-
|
388
|
-
it 'should support conjunction of two contradictory goals' do
|
389
|
-
subgoal1 = equals_goal(corn, ref_q)
|
390
|
-
subgoal2 = equals_goal(meal, ref_q)
|
391
|
-
goal = conj2_goal(subgoal1, subgoal2)
|
392
|
-
instance = RunStarExpression.new('q', goal)
|
393
|
-
|
394
|
-
# Reasoned S2, frame 1:53
|
395
|
-
# (run* q (conj2 (== 'corn q)(== 'meal q)) ;; => ()
|
396
|
-
expect(instance.run).to be_null
|
397
|
-
end
|
398
|
-
|
399
|
-
it 'should succeed the conjunction of two identical goals' do
|
400
|
-
subgoal1 = equals_goal(corn, ref_q)
|
401
|
-
subgoal2 = equals_goal(corn, ref_q)
|
402
|
-
goal = conj2_goal(subgoal1, subgoal2)
|
403
|
-
instance = RunStarExpression.new('q', goal)
|
166
|
+
subgoal = unify(corn, ref_q)
|
167
|
+
instance = RunStarExpression.new('q', conj2(succeeds, subgoal))
|
404
168
|
|
405
|
-
# Reasoned S2, frame 1:54
|
406
|
-
# (run* q (conj2 (== 'corn q)(== 'corn q)) ;; => ('corn)
|
407
169
|
result = instance.run
|
408
|
-
expect(result.
|
170
|
+
expect(result.to_s).to eq('(:corn)')
|
409
171
|
end
|
410
172
|
|
411
|
-
|
412
|
-
|
413
|
-
instance = RunStarExpression.new('q', goal)
|
414
|
-
|
415
|
-
# Reasoned S2, frame 1:55
|
416
|
-
# (run* q (disj2 fail fail)) ;; => ()
|
417
|
-
expect(instance.run).to be_null
|
418
|
-
end
|
419
|
-
|
420
|
-
it 'should yield solution when first argument succeed' do
|
421
|
-
subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
|
422
|
-
goal = disj2_goal(subgoal, fails)
|
423
|
-
instance = RunStarExpression.new('q', goal)
|
424
|
-
|
425
|
-
# Reasoned S2, frame 1:56
|
426
|
-
# (run* q (disj2 (== 'olive q) fail)) ;; => ('olive)
|
427
|
-
result = instance.run
|
428
|
-
expect(result.car).to eq(olive)
|
429
|
-
end
|
430
|
-
|
431
|
-
it 'should yield solution when second argument succeed' do
|
432
|
-
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
|
433
|
-
goal = disj2_goal(fails, subgoal)
|
434
|
-
instance = RunStarExpression.new('q', goal)
|
435
|
-
|
436
|
-
# Reasoned S2, frame 1:57
|
437
|
-
# (run* q (disj2 fail (== 'oil q))) ;; => (oil)
|
438
|
-
result = instance.run
|
439
|
-
expect(result.car).to eq(oil)
|
440
|
-
end
|
441
|
-
|
442
|
-
it 'should yield solutions when both arguments succeed' do
|
443
|
-
subgoal1 = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
|
444
|
-
subgoal2 = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
|
445
|
-
goal = disj2_goal(subgoal1, subgoal2)
|
446
|
-
instance = RunStarExpression.new('q', goal)
|
447
|
-
|
448
|
-
# Reasoned S2, frame 1:58
|
449
|
-
# (run* q (disj2 (== 'olive q) (== 'oil q))) ;; => (olive oil)
|
450
|
-
result = instance.run
|
451
|
-
expect(result.car).to eq(olive)
|
452
|
-
expect(result.cdr.car).to eq(oil)
|
453
|
-
end
|
454
|
-
|
455
|
-
it 'should support the nesting of variables and disjunction' do
|
456
|
-
# Reasoned S2, frame 1:59
|
457
|
-
# (run* q (fresh (x) (fresh (y) (disj2 (== '( ,x ,y ) q) (== '( ,x ,y ) q)))))
|
458
|
-
# ;; => ((_0 _1) (_0 _1))
|
459
|
-
expr1 = cons(ref_x, cons(ref_y))
|
460
|
-
subgoal1 = equals_goal(expr1, ref_q)
|
461
|
-
expr2 = cons(ref_y, cons(ref_x))
|
462
|
-
subgoal2 = equals_goal(expr2, ref_q)
|
463
|
-
goal = disj2_goal(subgoal1, subgoal2)
|
464
|
-
fresh_env_y = FreshEnv.new(['y'], goal)
|
465
|
-
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
466
|
-
instance = RunStarExpression.new('q', fresh_env_x)
|
467
|
-
|
468
|
-
result = instance.run
|
469
|
-
# q should be bound to '(,x ,y), then to '(,y ,x)
|
470
|
-
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
471
|
-
expect(result.cdr.car).to eq(cons(any_value(0), cons(any_value(1))))
|
472
|
-
end
|
473
|
-
|
474
|
-
it 'should accept nesting of disj2 and conj2 (I)' do
|
475
|
-
conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
476
|
-
conjunction = conj2_goal(conj_subgoal, fails)
|
477
|
-
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
478
|
-
goal = disj2_goal(conjunction, subgoal)
|
479
|
-
instance = RunStarExpression.new('x', goal)
|
480
|
-
|
481
|
-
# Reasoned S2, frame 1:62
|
482
|
-
# (run* x (disj2
|
483
|
-
# (conj2 (== 'olive x) fail)
|
484
|
-
# (== 'oil x))) ;; => (oil)
|
485
|
-
result = instance.run
|
486
|
-
expect(result.car).to eq(oil)
|
487
|
-
end
|
488
|
-
|
489
|
-
it 'should accept nesting of disj2 and conj2 (II)' do
|
490
|
-
conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
491
|
-
conjunction = conj2_goal(conj_subgoal, succeeds)
|
492
|
-
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
493
|
-
goal = disj2_goal(conjunction, subgoal)
|
494
|
-
instance = RunStarExpression.new('x', goal)
|
495
|
-
|
496
|
-
# Reasoned S2, frame 1:63
|
497
|
-
# (run* x (disj2
|
498
|
-
# (conj2 (== 'olive x) succeed)
|
499
|
-
# ('oil x))) ;; => (olive oil)
|
500
|
-
result = instance.run
|
501
|
-
expect(result.car).to eq(olive)
|
502
|
-
expect(result.cdr.car).to eq(oil)
|
503
|
-
end
|
504
|
-
|
505
|
-
it 'should accept nesting of disj2 and conj2 (III)' do
|
506
|
-
conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
507
|
-
conjunction = conj2_goal(conj_subgoal, succeeds)
|
508
|
-
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
509
|
-
goal = disj2_goal(subgoal, conjunction)
|
510
|
-
instance = RunStarExpression.new('x', goal)
|
511
|
-
|
512
|
-
# Reasoned S2, frame 1:64
|
513
|
-
# (run* x (disj2
|
514
|
-
# (== 'oil x)
|
515
|
-
# (conj2 (== 'olive x) succeed))) ;; => (oil olive)
|
516
|
-
result = instance.run
|
517
|
-
expect(result.car).to eq(oil)
|
518
|
-
expect(result.cdr.car).to eq(olive)
|
519
|
-
end
|
520
|
-
|
521
|
-
it 'should accept nesting of disj2 and conj2 (IV)' do
|
522
|
-
oil_goal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
523
|
-
disja = disj2_goal(succeeds, oil_goal)
|
524
|
-
olive_goal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
525
|
-
disjb = disj2_goal(olive_goal, disja)
|
526
|
-
virgin_goal = Core::Goal.new(Core::Equals.instance, [virgin, ref_x])
|
527
|
-
conjunction = conj2_goal(virgin_goal, fails)
|
528
|
-
goal = disj2_goal(conjunction, disjb)
|
529
|
-
instance = RunStarExpression.new('x', goal)
|
530
|
-
|
531
|
-
# Reasoned S2, frame 1:65
|
532
|
-
# (run* x (disj2
|
533
|
-
# (conj2(== 'virgin x) fail)
|
534
|
-
# (disj2
|
535
|
-
# (== 'olive x)
|
536
|
-
# (dis2
|
537
|
-
# succeed
|
538
|
-
# (== 'oil x))))) ;; => (olive _0 oil)
|
539
|
-
result = instance.run
|
540
|
-
expect(result.car).to eq(olive)
|
541
|
-
expect(result.cdr.car).to eq(any_value(0))
|
542
|
-
expect(result.cdr.cdr.car).to eq(oil)
|
543
|
-
end
|
544
|
-
|
545
|
-
it 'should accept nesting fresh, disj2 and conj2 expressions (I)' do
|
546
|
-
subgoal1 = equals_goal(split, ref_x)
|
547
|
-
expr1 = equals_goal(pea, ref_y)
|
548
|
-
expr2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
549
|
-
subgoal2 = conj2_goal(expr1, expr2)
|
550
|
-
goal = conj2_goal(subgoal1, subgoal2)
|
551
|
-
fresh_env_y = FreshEnv.new(['y'], goal)
|
552
|
-
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
553
|
-
instance = RunStarExpression.new('r', fresh_env_x)
|
554
|
-
|
555
|
-
# Reasoned S2, frame 1:67
|
556
|
-
# (run* r
|
557
|
-
# (fresh x
|
558
|
-
# (fresh y
|
559
|
-
# (conj2
|
560
|
-
# (== 'split x)
|
561
|
-
# (conj2
|
562
|
-
# (== 'pea y)
|
563
|
-
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
564
|
-
result = instance.run
|
565
|
-
expect(result.car.car).to eq(split)
|
566
|
-
expect(result.car.cdr.car).to eq(pea)
|
567
|
-
end
|
568
|
-
|
569
|
-
it 'should accept nesting fresh, disj2 and conj2 expressions (II)' do
|
570
|
-
expr1 = equals_goal(split, ref_x)
|
571
|
-
expr2 = equals_goal(pea, ref_y)
|
572
|
-
subgoal1 = conj2_goal(expr1, expr2)
|
573
|
-
subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
574
|
-
goal = conj2_goal(subgoal1, subgoal2)
|
575
|
-
fresh_env_y = FreshEnv.new(['y'], goal)
|
576
|
-
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
577
|
-
instance = RunStarExpression.new('r', fresh_env_x)
|
578
|
-
|
579
|
-
# Reasoned S2, frame 1:68
|
580
|
-
# (run* r
|
581
|
-
# (fresh x
|
582
|
-
# (fresh y
|
583
|
-
# (conj2
|
584
|
-
# (conj2
|
585
|
-
# (== 'split x)
|
586
|
-
# (== 'pea y)
|
587
|
-
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
588
|
-
result = instance.run
|
589
|
-
expect(result.car.car).to eq(split)
|
590
|
-
expect(result.car.cdr.car).to eq(pea)
|
591
|
-
end
|
592
|
-
|
593
|
-
it 'should accept fresh with multiple variables' do
|
594
|
-
expr1 = equals_goal(split, ref_x)
|
595
|
-
expr2 = equals_goal(pea, ref_y)
|
596
|
-
subgoal1 = conj2_goal(expr1, expr2)
|
597
|
-
subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
598
|
-
goal = conj2_goal(subgoal1, subgoal2)
|
599
|
-
fresh_env = FreshEnv.new(%w[x y], goal)
|
600
|
-
instance = RunStarExpression.new('r', fresh_env)
|
601
|
-
|
602
|
-
# Reasoned S2, frame 1:70
|
603
|
-
# (run* r
|
604
|
-
# (fresh (x y)
|
605
|
-
# (conj2
|
606
|
-
# (conj2
|
607
|
-
# (== 'split x)
|
608
|
-
# (== 'pea y)
|
609
|
-
# (== '(,x ,y) r))))) ;; => ((split pea))
|
610
|
-
result = instance.run
|
611
|
-
expect(result.car.car).to eq(split)
|
612
|
-
expect(result.car.cdr.car).to eq(pea)
|
613
|
-
end
|
614
|
-
|
615
|
-
it 'should accept multiple variables' do
|
616
|
-
expr1 = equals_goal(split, ref_x)
|
617
|
-
expr2 = equals_goal(pea, ref_y)
|
618
|
-
subgoal1 = conj2_goal(expr1, expr2)
|
619
|
-
subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
620
|
-
goal = conj2_goal(subgoal1, subgoal2)
|
621
|
-
instance = RunStarExpression.new(%w[r x y], goal)
|
622
|
-
|
623
|
-
# Reasoned S2, frame 1:72
|
624
|
-
# (run* (r x y)
|
625
|
-
# (conj2
|
626
|
-
# (conj2
|
627
|
-
# (== 'split x)
|
628
|
-
# (== 'pea y))
|
629
|
-
# (== '(,x ,y) r))) ;; => (((split pea) split pea))
|
630
|
-
# o
|
631
|
-
# / \
|
632
|
-
# o nil
|
633
|
-
# / \
|
634
|
-
# / \
|
635
|
-
# / \
|
636
|
-
# / \
|
637
|
-
# / \
|
638
|
-
# o o
|
639
|
-
# / \ / \
|
640
|
-
# split o split o
|
641
|
-
# / \ / \
|
642
|
-
# pea nil pea nil
|
643
|
-
result = instance.run
|
644
|
-
expect(result.car.car.car).to eq(split)
|
645
|
-
expect(result.car.car.cdr.car).to eq(pea)
|
646
|
-
expect(result.car.car.cdr.cdr).to be_nil
|
647
|
-
expect(result.car.cdr.car).to eq(split)
|
648
|
-
expect(result.car.cdr.cdr.car).to eq(pea)
|
649
|
-
expect(result.car.cdr.cdr.cdr).to be_nil
|
650
|
-
end
|
651
|
-
|
652
|
-
it 'should allow simplification of expressions' do
|
653
|
-
expr1 = equals_goal(split, ref_x)
|
654
|
-
expr2 = equals_goal(pea, ref_y)
|
655
|
-
goal = conj2_goal(expr1, expr2)
|
656
|
-
instance = RunStarExpression.new(%w[x y], goal)
|
657
|
-
|
658
|
-
# Reasoned S2, frame 1:75
|
659
|
-
# (run* (x y)
|
660
|
-
# (conj2
|
661
|
-
# (== 'split x)
|
662
|
-
# (== 'pea y))) ;; => ((split pea))
|
663
|
-
result = instance.run
|
664
|
-
expect(result.car.car).to eq(split)
|
665
|
-
expect(result.car.cdr.car).to eq(pea)
|
666
|
-
end
|
667
|
-
|
668
|
-
it 'should allow simplication of expressions' do
|
669
|
-
expr1 = equals_goal(split, ref_x)
|
670
|
-
expr2 = equals_goal(pea, ref_y)
|
671
|
-
subgoal1 = conj2_goal(expr1, expr2)
|
672
|
-
expr3 = equals_goal(red, ref_x)
|
673
|
-
expr4 = equals_goal(bean, ref_y)
|
674
|
-
subgoal2 = conj2_goal(expr3, expr4)
|
675
|
-
goal = disj2_goal(subgoal1, subgoal2)
|
676
|
-
instance = RunStarExpression.new(%w[x y], goal)
|
677
|
-
|
678
|
-
# Reasoned S2, frame 1:76
|
679
|
-
# (run* (x y)
|
680
|
-
# (disj2
|
681
|
-
# (conj2 (== 'split x) (== 'pea y))
|
682
|
-
# (conj2 (== 'red x) (== 'bean y)))) ;; => ((split pea)(red bean))
|
683
|
-
result = instance.run
|
684
|
-
expect(result.car.car).to eq(split)
|
685
|
-
expect(result.car.cdr.car).to eq(pea)
|
686
|
-
expect(result.cdr.car.car).to eq(red)
|
687
|
-
expect(result.cdr.car.cdr.car).to eq(bean)
|
688
|
-
end
|
689
|
-
|
690
|
-
it 'should allow nesting a disjunction inside of conjunction' do
|
691
|
-
expr1 = equals_goal(split, ref_x)
|
692
|
-
expr2 = equals_goal(red, ref_x)
|
693
|
-
subgoal1 = disj2_goal(expr1, expr2)
|
694
|
-
subgoal2 = equals_goal(ref_x, ref_y)
|
695
|
-
goal = conj2_goal(subgoal1, subgoal2)
|
696
|
-
instance = RunStarExpression.new(%w[x y], goal)
|
697
|
-
|
698
|
-
# (display (run* (x y)
|
699
|
-
# (conj2
|
700
|
-
# (disj2
|
701
|
-
# (== 'split x)
|
702
|
-
# (== 'red x))
|
703
|
-
# (== x y)))) ;; => ((split split) (red red))
|
704
|
-
result = instance.run
|
705
|
-
expect(result.car.car).to eq(split)
|
706
|
-
expect(result.car.cdr.car).to eq(split)
|
707
|
-
expect(result.cdr.car.cdr.car).to eq(red)
|
708
|
-
end
|
709
|
-
|
710
|
-
it 'should accept fresh with multiple variables' do
|
711
|
-
expr1 = equals_goal(split, ref_x)
|
712
|
-
expr2 = equals_goal(pea, ref_y)
|
713
|
-
subgoal1 = conj2_goal(expr1, expr2)
|
714
|
-
expr3 = equals_goal(red, ref_x)
|
715
|
-
expr4 = equals_goal(bean, ref_y)
|
716
|
-
subgoal2 = conj2_goal(expr3, expr4)
|
717
|
-
subgoal3 = disj2_goal(subgoal1, subgoal2)
|
718
|
-
subgoal4 = equals_goal(cons(ref_x, cons(ref_y, cons(soup))), ref_r)
|
719
|
-
goal = conj2_goal(subgoal3, subgoal4)
|
720
|
-
fresh_env = FreshEnv.new(%w[x y], goal)
|
721
|
-
instance = RunStarExpression.new('r', fresh_env)
|
722
|
-
|
723
|
-
# Reasoned S2, frame 1:77
|
724
|
-
# (run* r
|
725
|
-
# (fresh (x y)
|
726
|
-
# (conj2
|
727
|
-
# (disj2
|
728
|
-
# (conj2 (== 'split x) (== 'pea y))
|
729
|
-
# (conj2 (== 'red x) (== 'bean y)))
|
730
|
-
# (== '(,x ,y soup) r)))) ;; => ((split pea soup) (red bean soup))
|
731
|
-
result = instance.run
|
732
|
-
expect(result.car.car).to eq(split)
|
733
|
-
expect(result.car.cdr.car).to eq(pea)
|
734
|
-
expect(result.car.cdr.cdr.car).to eq(soup)
|
735
|
-
expect(result.cdr.car.car).to eq(red)
|
736
|
-
expect(result.cdr.car.cdr.car).to eq(bean)
|
737
|
-
expect(result.cdr.car.cdr.cdr.car).to eq(soup)
|
738
|
-
end
|
739
|
-
|
740
|
-
it 'should allow fresh with multiple goals' do
|
741
|
-
expr1 = equals_goal(split, ref_x)
|
742
|
-
expr2 = equals_goal(pea, ref_y)
|
743
|
-
subgoal1 = conj2_goal(expr1, expr2)
|
744
|
-
expr3 = equals_goal(red, ref_x)
|
745
|
-
expr4 = equals_goal(bean, ref_y)
|
746
|
-
subgoal2 = conj2_goal(expr3, expr4)
|
747
|
-
goal1 = disj2_goal(subgoal1, subgoal2)
|
748
|
-
goal2 = equals_goal(cons(ref_x, cons(ref_y, cons(soup))), ref_r)
|
749
|
-
fresh_env = FreshEnv.new(%w[x y], [goal1, goal2])
|
750
|
-
instance = RunStarExpression.new('r', fresh_env)
|
751
|
-
|
752
|
-
# Reasoned S2, frame 1:78
|
753
|
-
# (run* r
|
754
|
-
# (fresh (x y)
|
755
|
-
# (disj2
|
756
|
-
# (conj2 (== 'split x) (== 'pea y))
|
757
|
-
# (conj2 (== 'red x) (== 'bean y)))
|
758
|
-
# (== '(,x ,y soup) r))) ;; => ((split pea soup) (red bean soup))
|
759
|
-
result = instance.run
|
760
|
-
expect(result.car.car).to eq(split)
|
761
|
-
expect(result.car.cdr.car).to eq(pea)
|
762
|
-
expect(result.car.cdr.cdr.car).to eq(soup)
|
763
|
-
expect(result.cdr.car.car).to eq(red)
|
764
|
-
expect(result.cdr.car.cdr.car).to eq(bean)
|
765
|
-
expect(result.cdr.car.cdr.cdr.car).to eq(soup)
|
766
|
-
end
|
767
|
-
|
768
|
-
it 'should allow run* with multiple goals' do
|
769
|
-
expr1 = equals_goal(split, ref_x)
|
770
|
-
expr2 = equals_goal(pea, ref_y)
|
771
|
-
subgoal1 = conj2_goal(expr1, expr2)
|
772
|
-
expr3 = equals_goal(red, ref_x)
|
773
|
-
expr4 = equals_goal(bean, ref_y)
|
774
|
-
subgoal2 = conj2_goal(expr3, expr4)
|
775
|
-
goal1 = disj2_goal(subgoal1, subgoal2)
|
776
|
-
goal2 = equals_goal(soup, ref_z)
|
777
|
-
instance = RunStarExpression.new(%w[x y z], [goal1, goal2])
|
778
|
-
|
779
|
-
# Reasoned S2, frame 1:80
|
780
|
-
# (run* (x y z)
|
781
|
-
# (disj2
|
782
|
-
# (conj2 (== 'split x) (== 'pea y))
|
783
|
-
# (conj2 (== 'red x) (== 'bean y)))
|
784
|
-
# (== 'soup z)) ;; => ((split pea soup) (red bean soup))
|
785
|
-
result = instance.run
|
786
|
-
expect(result.car.car).to eq(split)
|
787
|
-
expect(result.car.cdr.car).to eq(pea)
|
788
|
-
expect(result.car.cdr.cdr.car).to eq(soup)
|
789
|
-
expect(result.cdr.car.car).to eq(red)
|
790
|
-
expect(result.cdr.car.cdr.car).to eq(bean)
|
791
|
-
expect(result.cdr.car.cdr.cdr.car).to eq(soup)
|
792
|
-
end
|
793
|
-
|
794
|
-
it 'should allow simplified expressions with multiple goals' do
|
795
|
-
expr1 = equals_goal(split, ref_x)
|
796
|
-
expr2 = equals_goal(pea, ref_y)
|
797
|
-
instance = RunStarExpression.new(%w[x y], [expr1, expr2])
|
798
|
-
|
799
|
-
# Reasoned S2, frame 1:81
|
800
|
-
# (run* (x y)
|
801
|
-
# (== 'split x)
|
802
|
-
# (== 'pea y)) ;; => ((split pea))
|
803
|
-
result = instance.run
|
804
|
-
expect(result.car.car).to eq(split)
|
805
|
-
expect(result.car.cdr.car).to eq(pea)
|
806
|
-
end
|
807
|
-
|
808
|
-
it 'should solve expression with defrel' do
|
809
|
-
teacupo_goal = Core::Goal.new(teacupo_rel, [ref_x])
|
810
|
-
|
811
|
-
# Reasoned S2, frame 1:83
|
812
|
-
# (run* x
|
813
|
-
# (teacupo x)) ;; => ((tea cup))
|
814
|
-
instance = RunStarExpression.new('x', teacupo_goal)
|
815
|
-
|
816
|
-
result = instance.run
|
817
|
-
expect(result.car).to eq(tea)
|
818
|
-
expect(result.cdr.car).to eq(cup)
|
819
|
-
end
|
820
|
-
|
821
|
-
it 'should solve expression with defrel and booleans' do
|
822
|
-
teacupo_goal = Core::Goal.new(teacupo_rel, [ref_x])
|
823
|
-
expr2 = equals_goal(k_true, ref_y)
|
824
|
-
subgoal1 = conj2_goal(teacupo_goal, expr2)
|
825
|
-
expr3 = equals_goal(k_false, ref_x)
|
826
|
-
expr4 = equals_goal(k_true, ref_y)
|
827
|
-
subgoal2 = conj2_goal(expr3, expr4)
|
828
|
-
goal = disj2_goal(subgoal1, subgoal2)
|
829
|
-
# Reasoned S2, frame 1:84
|
830
|
-
# (run* (x y)
|
831
|
-
# (disj2
|
832
|
-
# (conj2 (teacupo x) (== #t y))
|
833
|
-
# (conj2 (== #f x) (== #t y))) ;; => ((#f #t)(tea #t) (cup #t))
|
834
|
-
instance = RunStarExpression.new(%w[x y], goal)
|
835
|
-
|
836
|
-
result = instance.run
|
837
|
-
# Order of solutions differs from RS book
|
838
|
-
expect(result.car).to eq(cons(tea, cons(true)))
|
839
|
-
expect(result.cdr.car).to eq(cons(cup, cons(true)))
|
840
|
-
expect(result.cdr.cdr.car).to eq(cons(false, cons(true)))
|
841
|
-
end
|
842
|
-
|
843
|
-
it 'should solve expression with two variable and defrel' do
|
844
|
-
teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
|
845
|
-
teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_y])
|
846
|
-
|
847
|
-
# Reasoned S2, frame 1:85
|
848
|
-
# (run* (x y)
|
849
|
-
# (teacupo x)
|
850
|
-
# (teacupo y)) ;; => ((tea tea)(tea cup)(cup tea)(cup c))
|
851
|
-
instance = RunStarExpression.new(%w[x y], [teacupo_goal1, teacupo_goal2])
|
852
|
-
|
853
|
-
result = instance.run
|
854
|
-
expect(result.car).to eq(cons(tea, cons(tea)))
|
855
|
-
expect(result.cdr.car).to eq(cons(tea, cons(cup)))
|
856
|
-
expect(result.cdr.cdr.car).to eq(cons(cup, cons(tea)))
|
857
|
-
expect(result.cdr.cdr.cdr.car).to eq(cons(cup, cons(cup)))
|
858
|
-
end
|
859
|
-
|
860
|
-
it 'should solve expression with two variable and defrel' do
|
861
|
-
teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
|
862
|
-
teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_x])
|
863
|
-
|
864
|
-
# Reasoned S2, frame 1:86
|
865
|
-
# (run* (x y)
|
866
|
-
# (teacupo x)
|
867
|
-
# (teacupo x)) ;; => ((tea _0)(cup _0))
|
868
|
-
instance = RunStarExpression.new(%w[x y], [teacupo_goal1, teacupo_goal2])
|
869
|
-
|
870
|
-
result = instance.run
|
871
|
-
expect(result.car).to eq(cons(tea, cons(any_value(0))))
|
872
|
-
expect(result.cdr.car).to eq(cons(cup, cons(any_value(0))))
|
873
|
-
end
|
874
|
-
|
875
|
-
it 'should solve expression with defrel and booleans' do
|
876
|
-
teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
|
877
|
-
teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_x])
|
878
|
-
subgoal1 = conj2_goal(teacupo_goal1, teacupo_goal2)
|
879
|
-
expr3 = equals_goal(k_false, ref_x)
|
880
|
-
expr4 = Core::Goal.new(teacupo_rel, [ref_y])
|
881
|
-
subgoal2 = conj2_goal(expr3, expr4)
|
882
|
-
goal = disj2_goal(subgoal1, subgoal2)
|
883
|
-
# Reasoned S2, frame 1:87
|
884
|
-
# (run* (x y)
|
885
|
-
# (disj2
|
886
|
-
# (conj2 (teacupo x) (teacupo x))
|
887
|
-
# (conj2 (== #f x) (teacupo y)))) ;; => ((#f tea)(#f cup)(tea _0)(cup _0))
|
888
|
-
instance = RunStarExpression.new(%w[x y], goal)
|
889
|
-
|
890
|
-
result = instance.run
|
891
|
-
# Order of solutions differs from RS book
|
892
|
-
expect(result.car).to eq(cons(tea, cons(any_value(0))))
|
893
|
-
expect(result.cdr.car).to eq(cons(cup, cons(any_value(0))))
|
894
|
-
expect(result.cdr.cdr.car).to eq(cons(false, cons(tea)))
|
895
|
-
expect(result.cdr.cdr.cdr.car).to eq(cons(false, cons(cup)))
|
896
|
-
end
|
897
|
-
|
898
|
-
it 'should allow conde in the goal expression' do
|
899
|
-
teacupo_goal1 = Core::Goal.new(teacupo_rel, [ref_x])
|
900
|
-
teacupo_goal2 = Core::Goal.new(teacupo_rel, [ref_x])
|
901
|
-
expr3 = equals_goal(k_false, ref_x)
|
902
|
-
expr4 = Core::Goal.new(teacupo_rel, [ref_y])
|
903
|
-
goal = conde_goal([[teacupo_goal1, teacupo_goal2], [expr3, expr4]])
|
904
|
-
# Reasoned S2, frame 1:88
|
905
|
-
# (run* (x y)
|
906
|
-
# (conde
|
907
|
-
# ((teacupo x) (teacupo x))
|
908
|
-
# ((== #f x) (teacupo y)))) ;; => ((#f tea)(#f cup)(tea _0)(cup _0))
|
909
|
-
instance = RunStarExpression.new(%w[x y], goal)
|
910
|
-
|
911
|
-
result = instance.run
|
912
|
-
expect(result.car).to eq(cons(tea, cons(any_value(0))))
|
913
|
-
expect(result.cdr.car).to eq(cons(cup, cons(any_value(0))))
|
914
|
-
expect(result.cdr.cdr.car).to eq(cons(false, cons(tea)))
|
915
|
-
expect(result.cdr.cdr.cdr.car).to eq(cons(false, cons(cup)))
|
916
|
-
end
|
917
|
-
|
918
|
-
it 'should allow simplication of expressions (conde version)' do
|
919
|
-
expr1 = equals_goal(split, ref_x)
|
920
|
-
expr2 = equals_goal(pea, ref_y)
|
921
|
-
combo1 = [expr1, expr2]
|
922
|
-
expr3 = equals_goal(red, ref_x)
|
923
|
-
expr4 = equals_goal(bean, ref_y)
|
924
|
-
combo2 = [expr3, expr4]
|
925
|
-
goal = conde_goal([combo1, combo2])
|
926
|
-
instance = RunStarExpression.new(%w[x y], goal)
|
927
|
-
|
928
|
-
# Reasoned S2, frame 1:88 (second part, a rewrite of 1:76)
|
929
|
-
# (run* (x y)
|
930
|
-
# (conde
|
931
|
-
# ((== 'split x) (== 'pea y))
|
932
|
-
# ((== 'red x) (== 'bean y)))) ;; => ((split pea)(red bean))
|
933
|
-
result = instance.run
|
934
|
-
expect(result.car.car).to eq(split)
|
935
|
-
expect(result.car.cdr.car).to eq(pea)
|
936
|
-
expect(result.cdr.car.car).to eq(red)
|
937
|
-
expect(result.cdr.car.cdr.car).to eq(bean)
|
938
|
-
end
|
939
|
-
|
940
|
-
it 'should accept nesting of disj2 and conj2 (conde version)' do
|
941
|
-
equals_olive = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
942
|
-
combo = [equals_olive, fails]
|
943
|
-
equals_oil = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
944
|
-
goal = conde_goal([combo, equals_oil])
|
945
|
-
instance = RunStarExpression.new('x', goal)
|
946
|
-
|
947
|
-
# Reasoned S2, frame 1:89 (rewrite of 1:62)
|
948
|
-
# (run* x
|
949
|
-
# (conde
|
950
|
-
# ((== 'olive x) fail)
|
951
|
-
# ('oil x))) ;; => (oil)
|
952
|
-
result = instance.run
|
953
|
-
expect(result.car).to eq(oil)
|
954
|
-
end
|
955
|
-
|
956
|
-
it 'should accept nesting of conde inside a fresh context' do
|
957
|
-
equals_lentil = Core::Goal.new(Core::Equals.instance, [lentil, ref_z])
|
958
|
-
fresh_env = FreshEnv.new(['z'], equals_lentil)
|
959
|
-
equals_xy = Core::Goal.new(Core::Equals.instance, [ref_x, ref_y])
|
960
|
-
goal = conde_goal([fresh_env, equals_xy])
|
961
|
-
instance = RunStarExpression.new(%w[x y], goal)
|
962
|
-
fresh_env.parent = instance.env
|
963
|
-
|
964
|
-
# Reasoned S2, frame 1:90
|
965
|
-
# (run* (x y)
|
966
|
-
# (conde
|
967
|
-
# ((fresh (z)
|
968
|
-
# (== 'lentil z)))
|
969
|
-
# ((== x y)))) ;; => ((_0 _1)(_0 _0))
|
970
|
-
result = instance.run
|
971
|
-
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
972
|
-
expect(result.cdr.car).to eq(cons(any_value(0), cons(any_value(0))))
|
973
|
-
end
|
974
|
-
|
975
|
-
it 'accepts conde with more than two condition lines' do
|
976
|
-
expr1 = equals_goal(split, ref_x)
|
977
|
-
expr2 = equals_goal(pea, ref_y)
|
978
|
-
combo1 = [expr1, expr2]
|
979
|
-
expr3 = equals_goal(red, ref_x)
|
980
|
-
expr4 = equals_goal(bean, ref_y)
|
981
|
-
combo2 = [expr3, expr4]
|
982
|
-
expr5 = equals_goal(green, ref_x)
|
983
|
-
expr6 = equals_goal(lentil, ref_y)
|
984
|
-
combo3 = [expr5, expr6]
|
985
|
-
goal = conde_goal([combo1, combo2, combo3])
|
986
|
-
instance = RunStarExpression.new(%w[x y], goal)
|
987
|
-
|
988
|
-
# Reasoned S2, frame 1:91
|
989
|
-
# (run* (x y)
|
990
|
-
# (conde
|
991
|
-
# ((== 'split x) (== 'pea y))
|
992
|
-
# ((== 'red x) (== 'bean y))
|
993
|
-
# ((== 'green x) (== 'lentil y))))
|
994
|
-
# ;; => ((split pea)(red bean)(green lentil))
|
995
|
-
result = instance.run
|
996
|
-
expect(result.car).to eq(cons(split, cons(pea)))
|
997
|
-
expect(result.cdr.car).to eq(cons(red, cons(bean)))
|
998
|
-
expect(result.cdr.cdr.car).to eq(cons(green, cons(lentil)))
|
999
|
-
end
|
173
|
+
# TODO: add two solutions case
|
174
|
+
# TODO: add fused variables
|
1000
175
|
end # context
|
1001
176
|
end # describe
|
1002
177
|
end # module
|