mini_kraken 0.1.05 → 0.1.10
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 -0
- data/README.md +5 -3
- data/lib/mini_kraken/core/composite_goal.rb +46 -0
- data/lib/mini_kraken/core/composite_term.rb +2 -0
- data/lib/mini_kraken/core/conj2.rb +79 -0
- data/lib/mini_kraken/core/cons_cell.rb +49 -43
- data/lib/mini_kraken/core/designation.rb +55 -0
- data/lib/mini_kraken/core/disj2.rb +71 -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 -132
- data/lib/mini_kraken/core/fail.rb +18 -14
- data/lib/mini_kraken/core/goal.rb +4 -2
- data/lib/mini_kraken/core/goal_arg.rb +10 -0
- data/lib/mini_kraken/core/goal_relation.rb +28 -0
- data/lib/mini_kraken/core/outcome.rb +40 -24
- data/lib/mini_kraken/core/succeed.rb +17 -13
- data/lib/mini_kraken/core/term.rb +5 -2
- data/lib/mini_kraken/core/variable.rb +3 -27
- data/lib/mini_kraken/core/variable_ref.rb +3 -28
- data/lib/mini_kraken/core/vocabulary.rb +39 -19
- data/lib/mini_kraken/glue/fresh_env.rb +45 -3
- data/lib/mini_kraken/glue/run_star_expression.rb +44 -19
- data/lib/mini_kraken/version.rb +1 -1
- data/spec/core/conj2_spec.rb +114 -0
- data/spec/core/cons_cell_spec.rb +8 -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/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 +478 -53
- data/spec/mini_kraken_spec.rb +2 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/support/factory_methods.rb +16 -0
- metadata +14 -2
data/lib/mini_kraken/version.rb
CHANGED
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/k_symbol'
|
5
|
+
require_relative '../../lib/mini_kraken/core/fail'
|
6
|
+
require_relative '../../lib/mini_kraken/core/succeed'
|
7
|
+
require_relative '../../lib/mini_kraken/core/equals'
|
8
|
+
require_relative '../../lib/mini_kraken/core/environment'
|
9
|
+
require_relative '../../lib/mini_kraken/core/variable'
|
10
|
+
require_relative '../../lib/mini_kraken/core/variable_ref'
|
11
|
+
|
12
|
+
# Load the class under test
|
13
|
+
require_relative '../../lib/mini_kraken/core/conj2'
|
14
|
+
|
15
|
+
|
16
|
+
module MiniKraken
|
17
|
+
module Core
|
18
|
+
describe Conj2 do
|
19
|
+
subject { Conj2.instance }
|
20
|
+
|
21
|
+
context 'Initialization:' do
|
22
|
+
it 'should be initialized without argument' do
|
23
|
+
expect { Conj2.instance }.not_to raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should know its name' do
|
27
|
+
expect(subject.name).to eq('conj2')
|
28
|
+
end
|
29
|
+
end # context
|
30
|
+
|
31
|
+
context 'Provided services:' do
|
32
|
+
let(:env) { Environment.new }
|
33
|
+
let(:pea) { KSymbol.new(:pea) }
|
34
|
+
let(:corn) { KSymbol.new(:corn) }
|
35
|
+
let(:meal) { KSymbol.new(:meal) }
|
36
|
+
let(:fails) { Goal.new(Fail.instance, []) }
|
37
|
+
let(:succeeds) { Goal.new(Succeed.instance, []) }
|
38
|
+
let(:var_q) { Variable.new('q') }
|
39
|
+
let(:ref_q) { VariableRef.new('q') }
|
40
|
+
|
41
|
+
it 'should complain when one of its argument is not a goal' do
|
42
|
+
err = StandardError
|
43
|
+
expect { subject.solver_for([succeeds, pea], env) }.to raise_error(err)
|
44
|
+
expect { subject.solver_for([pea, succeeds], env) }.to raise_error(err)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should yield one failure if one of the goal is fail' do
|
48
|
+
# Fail as first argument
|
49
|
+
solver = subject.solver_for([fails, succeeds], env)
|
50
|
+
expect(solver.resume).not_to be_successful
|
51
|
+
expect(solver.resume).to be_nil
|
52
|
+
|
53
|
+
# Fail as second argument
|
54
|
+
solver = subject.solver_for([succeeds, fails], env)
|
55
|
+
expect(solver.resume).not_to be_successful
|
56
|
+
expect(solver.resume).to be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'yield success if both arguments are succeed goals' do
|
60
|
+
# Covers frame 1-50
|
61
|
+
solver = subject.solver_for([succeeds, succeeds], env)
|
62
|
+
outcome = solver.resume
|
63
|
+
expect(outcome).to be_successful
|
64
|
+
expect(outcome.associations).to be_empty
|
65
|
+
expect(solver.resume).to be_nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should yield success and set associations' do
|
69
|
+
# Covers frame 1-51
|
70
|
+
env.add_var(var_q)
|
71
|
+
sub_goal = Goal.new(Equals.instance, [corn, ref_q])
|
72
|
+
solver = subject.solver_for([succeeds, sub_goal], env)
|
73
|
+
outcome = solver.resume
|
74
|
+
expect(outcome).to be_successful
|
75
|
+
expect(outcome.associations).not_to be_empty
|
76
|
+
expect(outcome.associations['q'].first.value).to eq(corn)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should yield fails and set no associations' do
|
80
|
+
# Covers frame 1-52
|
81
|
+
env.add_var(var_q)
|
82
|
+
sub_goal = Goal.new(Equals.instance, [corn, ref_q])
|
83
|
+
solver = subject.solver_for([fails, sub_goal], env)
|
84
|
+
outcome = solver.resume
|
85
|
+
expect(outcome).not_to be_successful
|
86
|
+
expect(outcome.associations).to be_empty
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should yield fails when sub-goals are incompatible' do
|
90
|
+
# Covers frame 1-53
|
91
|
+
env.add_var(var_q)
|
92
|
+
sub_goal1 = Goal.new(Equals.instance, [corn, ref_q])
|
93
|
+
sub_goal2 = Goal.new(Equals.instance, [meal, ref_q])
|
94
|
+
solver = subject.solver_for([sub_goal1, sub_goal2], env)
|
95
|
+
outcome = solver.resume
|
96
|
+
expect(outcome).not_to be_successful
|
97
|
+
expect(outcome.associations).to be_empty
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should yield success when sub-goals are same and successful' do
|
101
|
+
# Covers frame 1-54
|
102
|
+
env.add_var(var_q)
|
103
|
+
sub_goal1 = Goal.new(Equals.instance, [corn, ref_q])
|
104
|
+
sub_goal2 = Goal.new(Equals.instance, [corn, ref_q])
|
105
|
+
solver = subject.solver_for([sub_goal1, sub_goal2], env)
|
106
|
+
outcome = solver.resume
|
107
|
+
expect(outcome).to be_successful
|
108
|
+
expect(outcome.associations).not_to be_empty
|
109
|
+
expect(outcome.associations['q'].first.value).to eq(corn)
|
110
|
+
end
|
111
|
+
end # context
|
112
|
+
end # describe
|
113
|
+
end # module
|
114
|
+
end # module
|
data/spec/core/cons_cell_spec.rb
CHANGED
@@ -58,6 +58,14 @@ module MiniKraken
|
|
58
58
|
different = ConsCell.new(pea)
|
59
59
|
expect(subject.eql?(different)).to be_falsey
|
60
60
|
end
|
61
|
+
|
62
|
+
it 'should append another cons cell' do
|
63
|
+
instance = ConsCell.new(pea)
|
64
|
+
trail = ConsCell.new(pod)
|
65
|
+
instance.append(trail)
|
66
|
+
expect(instance.car).to eq(pea)
|
67
|
+
expect(instance.cdr).to eq(trail)
|
68
|
+
end
|
61
69
|
end # context
|
62
70
|
end # describe
|
63
71
|
end # module
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/k_symbol'
|
5
|
+
require_relative '../../lib/mini_kraken/core/fail'
|
6
|
+
require_relative '../../lib/mini_kraken/core/succeed'
|
7
|
+
require_relative '../../lib/mini_kraken/core/equals'
|
8
|
+
require_relative '../../lib/mini_kraken/core/environment'
|
9
|
+
require_relative '../../lib/mini_kraken/core/variable'
|
10
|
+
require_relative '../../lib/mini_kraken/core/variable_ref'
|
11
|
+
|
12
|
+
# Load the class under test
|
13
|
+
require_relative '../../lib/mini_kraken/core/disj2'
|
14
|
+
|
15
|
+
module MiniKraken
|
16
|
+
module Core
|
17
|
+
describe Disj2 do
|
18
|
+
subject { Disj2.instance }
|
19
|
+
|
20
|
+
context 'Initialization:' do
|
21
|
+
it 'should be initialized without argument' do
|
22
|
+
expect { Disj2.instance }.not_to raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should know its name' do
|
26
|
+
expect(subject.name).to eq('disj2')
|
27
|
+
end
|
28
|
+
end # context
|
29
|
+
|
30
|
+
context 'Provided services:' do
|
31
|
+
let(:corn) { KSymbol.new(:corn) }
|
32
|
+
let(:meal) { KSymbol.new(:meal) }
|
33
|
+
let(:oil) { KSymbol.new(:oil) }
|
34
|
+
let(:olive) { KSymbol.new(:olive) }
|
35
|
+
let(:pea) { KSymbol.new(:pea) }
|
36
|
+
let(:fails) { Goal.new(Fail.instance, []) }
|
37
|
+
let(:succeeds) { Goal.new(Succeed.instance, []) }
|
38
|
+
let(:var_q) { Variable.new('q') }
|
39
|
+
let(:ref_q) { VariableRef.new('q') }
|
40
|
+
let(:env) do
|
41
|
+
e = Environment.new
|
42
|
+
e.add_var(var_q)
|
43
|
+
e
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should complain when one of its argument is not a goal' do
|
47
|
+
err = StandardError
|
48
|
+
expect { subject.solver_for([succeeds, pea], env) }.to raise_error(err)
|
49
|
+
expect { subject.solver_for([pea, succeeds], env) }.to raise_error(err)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should fails if both arguments fail' do
|
53
|
+
# Covers frame 1:55
|
54
|
+
solver = subject.solver_for([fails, fails], env)
|
55
|
+
expect(solver.resume).not_to be_successful
|
56
|
+
expect(solver.resume).to be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'yield success if first argument succeeds' do
|
60
|
+
# Covers frame 1:56
|
61
|
+
subgoal = Goal.new(Equals.instance, [olive, ref_q])
|
62
|
+
solver = subject.solver_for([subgoal, fails], env)
|
63
|
+
outcome = solver.resume
|
64
|
+
expect(outcome).to be_successful
|
65
|
+
expect(outcome.associations['q'].first.value).to eq(olive)
|
66
|
+
expect(solver.resume).to be_nil
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'yield success if second argument succeeds' do
|
70
|
+
# Covers frame 1:57
|
71
|
+
subgoal = Goal.new(Equals.instance, [oil, ref_q])
|
72
|
+
solver = subject.solver_for([fails, subgoal], env)
|
73
|
+
outcome = solver.resume
|
74
|
+
expect(outcome).to be_successful
|
75
|
+
expect(outcome.associations['q'].first.value).to eq(oil)
|
76
|
+
expect(solver.resume).to be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'yield two solutions if both arguments succeed' do
|
80
|
+
# Covers frame 1:58
|
81
|
+
subgoal1 = Goal.new(Equals.instance, [olive, ref_q])
|
82
|
+
subgoal2 = Goal.new(Equals.instance, [oil, ref_q])
|
83
|
+
solver = subject.solver_for([subgoal1, subgoal2], env)
|
84
|
+
|
85
|
+
# First solution
|
86
|
+
outcome1 = solver.resume
|
87
|
+
expect(outcome1).to be_successful
|
88
|
+
expect(outcome1.associations['q'].first.value).to eq(olive)
|
89
|
+
|
90
|
+
# Second solution
|
91
|
+
outcome2 = solver.resume
|
92
|
+
expect(outcome2).to be_successful
|
93
|
+
expect(outcome2.associations['q'].first.value).to eq(oil)
|
94
|
+
expect(solver.resume).to be_nil
|
95
|
+
end
|
96
|
+
end # context
|
97
|
+
end # describe
|
98
|
+
end # module
|
99
|
+
end # module
|
@@ -40,12 +40,23 @@ 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_successful
|
44
|
+
expect(outcome.parent).to be_nil
|
44
45
|
|
45
46
|
# Only one result should be yielded
|
46
47
|
expect(succeeding.resume).to be_nil
|
47
48
|
end
|
48
49
|
|
50
|
+
it 'should yield a distinct success object' do
|
51
|
+
instance1 = DuckFiber.new(:success)
|
52
|
+
outcome1 = instance1.resume
|
53
|
+
|
54
|
+
instance2 = DuckFiber.new(:success)
|
55
|
+
outcome2 = instance1.resume
|
56
|
+
|
57
|
+
expect(outcome1).not_to be_equal(outcome2)
|
58
|
+
end
|
59
|
+
|
49
60
|
it 'should behave like a Fiber yielding a custom outcome' do
|
50
61
|
tailored = DuckFiber.new(:custom) { Outcome.new(:"#s", parent) }
|
51
62
|
outcome = nil
|
data/spec/core/equals_spec.rb
CHANGED
@@ -275,9 +275,9 @@ module MiniKraken
|
|
275
275
|
|
276
276
|
it 'should unify composite terms with variables' do
|
277
277
|
# Reasoned S2, frame 1:36
|
278
|
-
# (run* q (fresh (x) (== '(((,q))
|
279
|
-
expr1 = cons(cons(ref_q), ref_x)
|
280
|
-
expr2 = cons(cons(ref_x), pod)
|
278
|
+
# (run* q (fresh (x) (== '(((,q)) ,x) `(((,x)) pod)))) ;; => ('pod)
|
279
|
+
expr1 = cons(cons(cons(ref_q)), ref_x)
|
280
|
+
expr2 = cons(cons(cons(ref_x)), pod)
|
281
281
|
|
282
282
|
result = solve_for(expr1, expr2)
|
283
283
|
# require 'debug'
|
@@ -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
|
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require_relative '../spec_helper' # Use the RSpec framework
|
4
4
|
require_relative '../../lib/mini_kraken/core/goal'
|
5
|
+
require_relative '../../lib/mini_kraken/core/conj2'
|
6
|
+
require_relative '../../lib/mini_kraken/core/disj2'
|
5
7
|
require_relative '../../lib/mini_kraken/core/equals'
|
6
8
|
require_relative '../../lib/mini_kraken/core/fail'
|
7
9
|
require_relative '../../lib/mini_kraken/core/succeed'
|
@@ -19,16 +21,26 @@ module MiniKraken
|
|
19
21
|
let(:pea) { k_symbol(:pea) }
|
20
22
|
let(:pod) { k_symbol(:pod) }
|
21
23
|
let(:sample_goal) { equals_goal(pea, pod) }
|
24
|
+
let(:fails) { Core::Goal.new(Core::Fail.instance, []) }
|
25
|
+
let(:succeeds) { Core::Goal.new(Core::Succeed.instance, []) }
|
22
26
|
subject { RunStarExpression.new('q', sample_goal) }
|
23
27
|
|
24
28
|
context 'Initialization:' do
|
25
|
-
it '
|
29
|
+
it 'could be initialized with a name and a goal' do
|
26
30
|
expect { RunStarExpression.new('q', sample_goal) }.not_to raise_error
|
27
31
|
end
|
28
32
|
|
33
|
+
it 'could be initialized with multiple names and a goal' do
|
34
|
+
expect { RunStarExpression.new(%w[r x y], sample_goal) }.not_to raise_error
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'could be initialized with multiple names and goals' do
|
38
|
+
expect { RunStarExpression.new(%w[r x y], [succeeds, succeeds]) }.not_to raise_error
|
39
|
+
end
|
40
|
+
|
29
41
|
it 'should know its variables' do
|
30
42
|
expect(subject.env.vars['q']).not_to be_nil
|
31
|
-
expect(subject.
|
43
|
+
expect(subject.env.vars.values[0].name).to eq('q')
|
32
44
|
end
|
33
45
|
|
34
46
|
it 'should know its goal' do
|
@@ -37,12 +49,23 @@ module MiniKraken
|
|
37
49
|
end # context
|
38
50
|
|
39
51
|
context 'Provided services:' do
|
52
|
+
let(:bean) { k_symbol(:bean) }
|
53
|
+
let(:corn) { k_symbol(:corn) }
|
54
|
+
let(:meal) { k_symbol(:meal) }
|
55
|
+
let(:oil) { k_symbol(:oil) }
|
56
|
+
let(:olive) { k_symbol(:olive) }
|
57
|
+
let(:red) { k_symbol(:red) }
|
58
|
+
let(:soup) { k_symbol(:soup) }
|
59
|
+
let(:split) { k_symbol(:split) }
|
60
|
+
let(:virgin) { k_symbol(:virgin) }
|
40
61
|
let(:ref_q) { Core::VariableRef.new('q') }
|
62
|
+
let(:ref_r) { Core::VariableRef.new('r') }
|
41
63
|
let(:ref_x) { Core::VariableRef.new('x') }
|
42
64
|
let(:ref_y) { Core::VariableRef.new('y') }
|
43
65
|
let(:ref_s) { Core::VariableRef.new('s') }
|
44
66
|
let(:ref_t) { Core::VariableRef.new('t') }
|
45
67
|
let(:ref_u) { Core::VariableRef.new('u') }
|
68
|
+
let(:ref_z) { Core::VariableRef.new('z') }
|
46
69
|
|
47
70
|
it 'should return a null list with the fail goal' do
|
48
71
|
# Reasoned S2, frame 1:7
|
@@ -51,7 +74,6 @@ module MiniKraken
|
|
51
74
|
instance = RunStarExpression.new('q', failing)
|
52
75
|
|
53
76
|
expect(instance.run).to be_null
|
54
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
55
77
|
end
|
56
78
|
|
57
79
|
it 'should return a null list when a goal fails' do
|
@@ -69,7 +91,6 @@ module MiniKraken
|
|
69
91
|
# Reasoned S2, frame 1:11
|
70
92
|
# (run* q (== q 'pea) ;; => (pea)
|
71
93
|
expect(instance.run.car).to eq(pea)
|
72
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
73
94
|
end
|
74
95
|
|
75
96
|
it 'should unify the righthand variable(s)' do
|
@@ -79,19 +100,14 @@ module MiniKraken
|
|
79
100
|
# Reasoned S2, frame 1:12
|
80
101
|
# (run* q (== 'pea q) ;; => (pea)
|
81
102
|
expect(instance.run.car).to eq(pea)
|
82
|
-
|
83
|
-
# Reasoned S2, frame 1:15
|
84
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
85
103
|
end
|
86
104
|
|
87
105
|
it 'should return a null list with the succeed goal' do
|
88
|
-
|
89
|
-
instance = RunStarExpression.new('q', success)
|
106
|
+
instance = RunStarExpression.new('q', succeeds)
|
90
107
|
|
91
108
|
# (display (run* q succeed)) ;; => (_0)
|
92
109
|
# Reasoned S2, frame 1:16
|
93
110
|
result = instance.run
|
94
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
95
111
|
|
96
112
|
# Reasoned S2, frame 1:17
|
97
113
|
expect(result.car).to eq(any_value(0))
|
@@ -104,7 +120,6 @@ module MiniKraken
|
|
104
120
|
# (display (run* q (== 'pea 'pea))) ;; => (_0)
|
105
121
|
# Reasoned S2, frame 1:19
|
106
122
|
result = instance.run
|
107
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
108
123
|
expect(result.car).to eq(any_value(0))
|
109
124
|
end
|
110
125
|
|
@@ -117,7 +132,6 @@ module MiniKraken
|
|
117
132
|
# (display (run* q (== q q))) ;; => (_0)
|
118
133
|
# Reasoned S2, frame 1:20
|
119
134
|
result = instance.run
|
120
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
121
135
|
expect(result.car).to eq(any_value(0))
|
122
136
|
end
|
123
137
|
|
@@ -129,8 +143,6 @@ module MiniKraken
|
|
129
143
|
# Reasoned S2, frame 1:21..23
|
130
144
|
# (run* q (fresh (x) (== 'pea q))) ;; => (pea)
|
131
145
|
result = instance.run
|
132
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
133
|
-
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
134
146
|
|
135
147
|
# Reasoned S2, frame 1:40
|
136
148
|
expect(ref_q.different_from?(ref_x, fresh_env)).to be_truthy
|
@@ -145,8 +157,6 @@ module MiniKraken
|
|
145
157
|
# Reasoned S2, frame 1:24
|
146
158
|
# (run* q (fresh (x) (== 'pea x))) ;; => (_0)
|
147
159
|
result = instance.run
|
148
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
149
|
-
expect(ref_x.fresh?(fresh_env)).to be_falsey
|
150
160
|
expect(result.car).to eq(any_value(0))
|
151
161
|
end
|
152
162
|
|
@@ -158,8 +168,6 @@ module MiniKraken
|
|
158
168
|
# Reasoned S2, frame 1:25
|
159
169
|
# (run* q (fresh (x) (== (cons x '()) q))) ;; => ((_0))
|
160
170
|
result = instance.run
|
161
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
162
|
-
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
163
171
|
expect(result.car).to eq(cons(any_value(0)))
|
164
172
|
end
|
165
173
|
|
@@ -190,7 +198,6 @@ module MiniKraken
|
|
190
198
|
# Reasoned S2, frame 1:32
|
191
199
|
# (run* q (== '(((pea)) pod) '(((pea)) pod))) ;; => (_0)
|
192
200
|
result = instance.run
|
193
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
194
201
|
expect(result.car).to eq(any_value(0))
|
195
202
|
end
|
196
203
|
|
@@ -204,7 +211,6 @@ module MiniKraken
|
|
204
211
|
# Reasoned S2, frame 1:33
|
205
212
|
# (run* q (== '(((pea)) pod) `(((pea)) ,q))) ;; => ('pod)
|
206
213
|
result = instance.run
|
207
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
208
214
|
expect(result.car).to eq(pod)
|
209
215
|
end
|
210
216
|
|
@@ -217,7 +223,6 @@ module MiniKraken
|
|
217
223
|
# Reasoned S2, frame 1:34
|
218
224
|
# (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pod)
|
219
225
|
result = instance.run
|
220
|
-
expect(ref_q.fresh?(instance.env)).to be_falsey
|
221
226
|
expect(result.car).to eq(pea)
|
222
227
|
end
|
223
228
|
|
@@ -231,8 +236,6 @@ module MiniKraken
|
|
231
236
|
# Reasoned S2, frame 1:35
|
232
237
|
# (run* q (fresh (x) (== '(((,q)) pod) `(((,x)) pod)))) ;; => (_0)
|
233
238
|
result = instance.run
|
234
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy
|
235
|
-
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
236
239
|
expect(result.car).to eq(any_value(0))
|
237
240
|
end
|
238
241
|
|
@@ -246,11 +249,6 @@ module MiniKraken
|
|
246
249
|
instance = RunStarExpression.new('q', fresh_env)
|
247
250
|
|
248
251
|
result = instance.run
|
249
|
-
|
250
|
-
# Does propagate work correctly?
|
251
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy # x isn't defined here
|
252
|
-
expect(ref_q.fresh?(fresh_env)).to be_falsey
|
253
|
-
expect(ref_x.fresh?(fresh_env)).to be_falsey
|
254
252
|
expect(result.car).to eq(pod)
|
255
253
|
end
|
256
254
|
|
@@ -263,9 +261,6 @@ module MiniKraken
|
|
263
261
|
instance = RunStarExpression.new('q', fresh_env)
|
264
262
|
|
265
263
|
result = instance.run
|
266
|
-
expect(ref_q.fresh?(instance.env)).to be_truthy # x isn't defined here
|
267
|
-
expect(ref_q.fresh?(fresh_env)).to be_truthy
|
268
|
-
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
269
264
|
expect(result.car).to eq(cons(any_value(0), cons(any_value(0))))
|
270
265
|
end
|
271
266
|
|
@@ -280,12 +275,6 @@ module MiniKraken
|
|
280
275
|
instance = RunStarExpression.new('q', fresh_env_x)
|
281
276
|
|
282
277
|
result = instance.run
|
283
|
-
expect(ref_q.fresh?(fresh_env_y)).to be_truthy
|
284
|
-
expect(ref_q.bound?(fresh_env_y)).to be_truthy
|
285
|
-
expect(ref_x.fresh?(fresh_env_y)).to be_truthy
|
286
|
-
expect(ref_x.bound?(fresh_env_y)).to be_falsy
|
287
|
-
expect(ref_y.fresh?(fresh_env_y)).to be_truthy
|
288
|
-
expect(ref_y.bound?(fresh_env_y)).to be_falsy
|
289
278
|
|
290
279
|
# y should be fused with x...
|
291
280
|
var_x = fresh_env_y.name2var('x')
|
@@ -309,13 +298,7 @@ module MiniKraken
|
|
309
298
|
instance = RunStarExpression.new('q', fresh_env_x)
|
310
299
|
|
311
300
|
result = instance.run
|
312
|
-
expect(ref_q.fresh?(fresh_env_y)).to be_truthy
|
313
301
|
# q should be bound to '(,x ,y)
|
314
|
-
expect(ref_q.bound?(fresh_env_y)).to be_truthy
|
315
|
-
expect(ref_x.fresh?(fresh_env_y)).to be_truthy
|
316
|
-
expect(ref_x.bound?(fresh_env_y)).to be_falsey
|
317
|
-
expect(ref_y.fresh?(fresh_env_y)).to be_truthy
|
318
|
-
expect(ref_y.bound?(fresh_env_y)).to be_falsey
|
319
302
|
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
320
303
|
end
|
321
304
|
|
@@ -329,13 +312,7 @@ module MiniKraken
|
|
329
312
|
instance = RunStarExpression.new('s', fresh_env_t)
|
330
313
|
|
331
314
|
result = instance.run
|
332
|
-
expect(ref_s.fresh?(fresh_env_u)).to be_truthy
|
333
315
|
# s should be bound to '(,t ,u)
|
334
|
-
expect(ref_s.bound?(fresh_env_u)).to be_truthy
|
335
|
-
expect(ref_t.fresh?(fresh_env_u)).to be_truthy
|
336
|
-
expect(ref_t.bound?(fresh_env_u)).to be_falsey
|
337
|
-
expect(ref_u.fresh?(fresh_env_u)).to be_truthy
|
338
|
-
expect(ref_u.bound?(fresh_env_u)).to be_falsey
|
339
316
|
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
340
317
|
end
|
341
318
|
|
@@ -349,13 +326,461 @@ module MiniKraken
|
|
349
326
|
instance = RunStarExpression.new('q', fresh_env_x)
|
350
327
|
|
351
328
|
result = instance.run
|
352
|
-
expect(ref_q.fresh?(fresh_env_y)).to be_truthy
|
353
329
|
# q should be bound to '(,x ,y, ,x)
|
354
|
-
expect(ref_q.bound?(fresh_env_y)).to be_truthy
|
355
|
-
expect(ref_x.fresh?(fresh_env_y)).to be_truthy
|
356
|
-
expect(ref_y.fresh?(fresh_env_y)).to be_truthy
|
357
330
|
expect(result.car).to eq(cons(any_value(0), cons(any_value(1), cons(any_value(0)))))
|
358
331
|
end
|
332
|
+
|
333
|
+
it 'should support conjunction of two succeed' do
|
334
|
+
goal = conj2_goal(succeeds, succeeds)
|
335
|
+
instance = RunStarExpression.new('q', goal)
|
336
|
+
|
337
|
+
# Reasoned S2, frame 1:50
|
338
|
+
# (run* q (conj2 succeed succeed)) ;; => (_0)
|
339
|
+
result = instance.run
|
340
|
+
expect(result.car).to eq(any_value(0))
|
341
|
+
end
|
342
|
+
|
343
|
+
# TODO: fix erratic RSpec failure
|
344
|
+
it 'should support conjunction of one succeed and a successful goal' do
|
345
|
+
subgoal = equals_goal(corn, ref_q)
|
346
|
+
goal = conj2_goal(succeeds, subgoal)
|
347
|
+
instance = RunStarExpression.new('q', goal)
|
348
|
+
|
349
|
+
# Reasoned S2, frame 1:51
|
350
|
+
# (run* q (conj2 succeed (== 'corn q)) ;; => ('corn)
|
351
|
+
result = instance.run
|
352
|
+
expect(result.car).to eq(corn)
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'should support conjunction of one fail and a successful goal' do
|
356
|
+
subgoal = equals_goal(corn, ref_q)
|
357
|
+
goal = conj2_goal(fails, subgoal)
|
358
|
+
instance = RunStarExpression.new('q', goal)
|
359
|
+
|
360
|
+
# Reasoned S2, frame 1:52
|
361
|
+
# (run* q (conj2 fail (== 'corn q)) ;; => ()
|
362
|
+
expect(instance.run).to be_null
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'should support conjunction of two contradictory goals' do
|
366
|
+
subgoal1 = equals_goal(corn, ref_q)
|
367
|
+
subgoal2 = equals_goal(meal, ref_q)
|
368
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
369
|
+
instance = RunStarExpression.new('q', goal)
|
370
|
+
|
371
|
+
# Reasoned S2, frame 1:53
|
372
|
+
# (run* q (conj2 (== 'corn q)(== 'meal q)) ;; => ()
|
373
|
+
expect(instance.run).to be_null
|
374
|
+
end
|
375
|
+
|
376
|
+
it 'should succeed the conjunction of two identical goals' do
|
377
|
+
subgoal1 = equals_goal(corn, ref_q)
|
378
|
+
subgoal2 = equals_goal(corn, ref_q)
|
379
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
380
|
+
instance = RunStarExpression.new('q', goal)
|
381
|
+
|
382
|
+
# Reasoned S2, frame 1:54
|
383
|
+
# (run* q (conj2 (== 'corn q)(== 'corn q)) ;; => ('corn)
|
384
|
+
result = instance.run
|
385
|
+
expect(result.car).to eq(corn)
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'should not yield solution when both disjunction arguments fail' do
|
389
|
+
goal = disj2_goal(fails, fails)
|
390
|
+
instance = RunStarExpression.new('q', goal)
|
391
|
+
|
392
|
+
# Reasoned S2, frame 1:55
|
393
|
+
# (run* q (disj2 fail fail)) ;; => ()
|
394
|
+
expect(instance.run).to be_null
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'should yield solution when first argument succeed' do
|
398
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
|
399
|
+
goal = disj2_goal(subgoal, fails)
|
400
|
+
instance = RunStarExpression.new('q', goal)
|
401
|
+
|
402
|
+
# Reasoned S2, frame 1:56
|
403
|
+
# (run* q (disj2 (== 'olive q) fail)) ;; => ('olive)
|
404
|
+
result = instance.run
|
405
|
+
expect(result.car).to eq(olive)
|
406
|
+
end
|
407
|
+
|
408
|
+
it 'should yield solution when second argument succeed' do
|
409
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
|
410
|
+
goal = disj2_goal(fails, subgoal)
|
411
|
+
instance = RunStarExpression.new('q', goal)
|
412
|
+
|
413
|
+
# Reasoned S2, frame 1:57
|
414
|
+
# (run* q (disj2 fail (== 'oil q))) ;; => (oil)
|
415
|
+
result = instance.run
|
416
|
+
expect(result.car).to eq(oil)
|
417
|
+
end
|
418
|
+
|
419
|
+
it 'should yield solutions when both arguments succeed' do
|
420
|
+
subgoal1 = Core::Goal.new(Core::Equals.instance, [olive, ref_q])
|
421
|
+
subgoal2 = Core::Goal.new(Core::Equals.instance, [oil, ref_q])
|
422
|
+
goal = disj2_goal(subgoal1, subgoal2)
|
423
|
+
instance = RunStarExpression.new('q', goal)
|
424
|
+
|
425
|
+
# Reasoned S2, frame 1:58
|
426
|
+
# (run* q (disj2 (== 'olive q) (== 'oil q))) ;; => (olive oil)
|
427
|
+
result = instance.run
|
428
|
+
expect(result.car).to eq(olive)
|
429
|
+
expect(result.cdr.car).to eq(oil)
|
430
|
+
end
|
431
|
+
|
432
|
+
it 'should support the nesting of variables and disjunction' do
|
433
|
+
# Reasoned S2, frame 1:59
|
434
|
+
# (run* q (fresh (x) (fresh (y) (disj2 (== '( ,x ,y ) q) (== '( ,x ,y ) q)))))
|
435
|
+
# ;; => ((_0 _1) (_0 _1))
|
436
|
+
expr1 = cons(ref_x, cons(ref_y))
|
437
|
+
subgoal1 = equals_goal(expr1, ref_q)
|
438
|
+
expr2 = cons(ref_y, cons(ref_x))
|
439
|
+
subgoal2 = equals_goal(expr2, ref_q)
|
440
|
+
goal = disj2_goal(subgoal1, subgoal2)
|
441
|
+
fresh_env_y = FreshEnv.new(['y'], goal)
|
442
|
+
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
443
|
+
instance = RunStarExpression.new('q', fresh_env_x)
|
444
|
+
|
445
|
+
result = instance.run
|
446
|
+
# q should be bound to '(,x ,y), then to '(,y ,x)
|
447
|
+
expect(result.car).to eq(cons(any_value(0), cons(any_value(1))))
|
448
|
+
expect(result.cdr.car).to eq(cons(any_value(0), cons(any_value(1))))
|
449
|
+
end
|
450
|
+
|
451
|
+
it 'should accept nesting of disj2 and conj2 (I)' do
|
452
|
+
conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
453
|
+
conjunction = conj2_goal(conj_subgoal, fails)
|
454
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
455
|
+
goal = disj2_goal(conjunction, subgoal)
|
456
|
+
instance = RunStarExpression.new('x', goal)
|
457
|
+
|
458
|
+
# Reasoned S2, frame 1:62
|
459
|
+
# (run* x (disj2
|
460
|
+
# (conj2 (== 'olive x) fail)
|
461
|
+
# ('oil x))) ;; => (oil)
|
462
|
+
result = instance.run
|
463
|
+
expect(result.car).to eq(oil)
|
464
|
+
end
|
465
|
+
|
466
|
+
it 'should accept nesting of disj2 and conj2 (II)' do
|
467
|
+
conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
468
|
+
conjunction = conj2_goal(conj_subgoal, succeeds)
|
469
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
470
|
+
goal = disj2_goal(conjunction, subgoal)
|
471
|
+
instance = RunStarExpression.new('x', goal)
|
472
|
+
|
473
|
+
# Reasoned S2, frame 1:63
|
474
|
+
# (run* x (disj2
|
475
|
+
# (conj2 (== 'olive x) succeed)
|
476
|
+
# ('oil x))) ;; => (olive oil)
|
477
|
+
result = instance.run
|
478
|
+
expect(result.car).to eq(olive)
|
479
|
+
expect(result.cdr.car).to eq(oil)
|
480
|
+
end
|
481
|
+
|
482
|
+
it 'should accept nesting of disj2 and conj2 (III)' do
|
483
|
+
conj_subgoal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
484
|
+
conjunction = conj2_goal(conj_subgoal, succeeds)
|
485
|
+
subgoal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
486
|
+
goal = disj2_goal(subgoal, conjunction)
|
487
|
+
instance = RunStarExpression.new('x', goal)
|
488
|
+
|
489
|
+
# Reasoned S2, frame 1:64
|
490
|
+
# (run* x (disj2
|
491
|
+
# ('oil x)
|
492
|
+
# (conj2 (== 'olive x) succeed))) ;; => (oil olive)
|
493
|
+
result = instance.run
|
494
|
+
expect(result.car).to eq(oil)
|
495
|
+
expect(result.cdr.car).to eq(olive)
|
496
|
+
end
|
497
|
+
|
498
|
+
it 'should accept nesting of disj2 and conj2 (IV)' do
|
499
|
+
oil_goal = Core::Goal.new(Core::Equals.instance, [oil, ref_x])
|
500
|
+
disja = disj2_goal(succeeds, oil_goal)
|
501
|
+
olive_goal = Core::Goal.new(Core::Equals.instance, [olive, ref_x])
|
502
|
+
disjb = disj2_goal(olive_goal, disja)
|
503
|
+
virgin_goal = Core::Goal.new(Core::Equals.instance, [virgin, ref_x])
|
504
|
+
conjunction = conj2_goal(virgin_goal, fails)
|
505
|
+
goal = disj2_goal(conjunction, disjb)
|
506
|
+
instance = RunStarExpression.new('x', goal)
|
507
|
+
|
508
|
+
# Reasoned S2, frame 1:65
|
509
|
+
# (run* x (disj2
|
510
|
+
# (conj2(== 'virgin x) fails)
|
511
|
+
# (disj2
|
512
|
+
# (== 'olive x)
|
513
|
+
# (dis2
|
514
|
+
# succeeds
|
515
|
+
# (== 'oil x))))) ;; => (olive _0 oil)
|
516
|
+
result = instance.run
|
517
|
+
expect(result.car).to eq(olive)
|
518
|
+
expect(result.cdr.car).to eq(any_value(0))
|
519
|
+
expect(result.cdr.cdr.car).to eq(oil)
|
520
|
+
end
|
521
|
+
|
522
|
+
it 'should accept nesting fresh, disj2 and conj2 expressions (I)' do
|
523
|
+
subgoal1 = equals_goal(split, ref_x)
|
524
|
+
expr1 = equals_goal(pea, ref_y)
|
525
|
+
expr2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
526
|
+
subgoal2 = conj2_goal(expr1, expr2)
|
527
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
528
|
+
fresh_env_y = FreshEnv.new(['y'], goal)
|
529
|
+
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
530
|
+
instance = RunStarExpression.new('r', fresh_env_x)
|
531
|
+
|
532
|
+
# Reasoned S2, frame 1:67
|
533
|
+
# (run* r
|
534
|
+
# (fresh x
|
535
|
+
# (fresh y
|
536
|
+
# (conj2
|
537
|
+
# (== 'split x)
|
538
|
+
# (conj2
|
539
|
+
# (== 'pea y)
|
540
|
+
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
541
|
+
result = instance.run
|
542
|
+
expect(result.car.car).to eq(split)
|
543
|
+
expect(result.car.cdr.car).to eq(pea)
|
544
|
+
end
|
545
|
+
|
546
|
+
it 'should accept nesting fresh, disj2 and conj2 expressions (II)' do
|
547
|
+
expr1 = equals_goal(split, ref_x)
|
548
|
+
expr2 = equals_goal(pea, ref_y)
|
549
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
550
|
+
subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
551
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
552
|
+
fresh_env_y = FreshEnv.new(['y'], goal)
|
553
|
+
fresh_env_x = FreshEnv.new(['x'], fresh_env_y)
|
554
|
+
instance = RunStarExpression.new('r', fresh_env_x)
|
555
|
+
|
556
|
+
# Reasoned S2, frame 1:68
|
557
|
+
# (run* r
|
558
|
+
# (fresh x
|
559
|
+
# (fresh y
|
560
|
+
# (conj2
|
561
|
+
# (conj2
|
562
|
+
# (== 'split x)
|
563
|
+
# (== 'pea y)
|
564
|
+
# (== '(,x ,y) r)))))) ;; => ((split pea))
|
565
|
+
result = instance.run
|
566
|
+
expect(result.car.car).to eq(split)
|
567
|
+
expect(result.car.cdr.car).to eq(pea)
|
568
|
+
end
|
569
|
+
|
570
|
+
it 'should accept fresh with multiple variables' do
|
571
|
+
expr1 = equals_goal(split, ref_x)
|
572
|
+
expr2 = equals_goal(pea, ref_y)
|
573
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
574
|
+
subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
575
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
576
|
+
fresh_env = FreshEnv.new(%w[x y], goal)
|
577
|
+
instance = RunStarExpression.new('r', fresh_env)
|
578
|
+
|
579
|
+
# Reasoned S2, frame 1:70
|
580
|
+
# (run* r
|
581
|
+
# (fresh (x y)
|
582
|
+
# (conj2
|
583
|
+
# (conj2
|
584
|
+
# (== 'split x)
|
585
|
+
# (== 'pea y)
|
586
|
+
# (== '(,x ,y) r))))) ;; => ((split pea))
|
587
|
+
result = instance.run
|
588
|
+
expect(result.car.car).to eq(split)
|
589
|
+
expect(result.car.cdr.car).to eq(pea)
|
590
|
+
end
|
591
|
+
|
592
|
+
it 'should accept multiple variables' do
|
593
|
+
expr1 = equals_goal(split, ref_x)
|
594
|
+
expr2 = equals_goal(pea, ref_y)
|
595
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
596
|
+
subgoal2 = equals_goal(cons(ref_x, cons(ref_y)), ref_r)
|
597
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
598
|
+
instance = RunStarExpression.new(%w[r x y], goal)
|
599
|
+
|
600
|
+
# Reasoned S2, frame 1:72
|
601
|
+
# (run* (r x y)
|
602
|
+
# (conj2
|
603
|
+
# (conj2
|
604
|
+
# (== 'split x)
|
605
|
+
# (== 'pea y))
|
606
|
+
# (== '(,x ,y) r))) ;; => (((split pea) split pea))
|
607
|
+
# o
|
608
|
+
# / \
|
609
|
+
# o nil
|
610
|
+
# / \
|
611
|
+
# / \
|
612
|
+
# / \
|
613
|
+
# / \
|
614
|
+
# / \
|
615
|
+
# o o
|
616
|
+
# / \ / \
|
617
|
+
# split o split o
|
618
|
+
# / \ / \
|
619
|
+
# pea nil pea nil
|
620
|
+
result = instance.run
|
621
|
+
expect(result.car.car.car).to eq(split)
|
622
|
+
expect(result.car.car.cdr.car).to eq(pea)
|
623
|
+
expect(result.car.car.cdr.cdr).to be_nil
|
624
|
+
expect(result.car.cdr.car).to eq(split)
|
625
|
+
expect(result.car.cdr.cdr.car).to eq(pea)
|
626
|
+
expect(result.car.cdr.cdr.cdr).to be_nil
|
627
|
+
end
|
628
|
+
|
629
|
+
it 'should allow simplication of expressions' do
|
630
|
+
expr1 = equals_goal(split, ref_x)
|
631
|
+
expr2 = equals_goal(pea, ref_y)
|
632
|
+
goal = conj2_goal(expr1, expr2)
|
633
|
+
instance = RunStarExpression.new(%w[x y], goal)
|
634
|
+
|
635
|
+
# Reasoned S2, frame 1:75
|
636
|
+
# (run* (x y)
|
637
|
+
# (conj2
|
638
|
+
# (== 'split x)
|
639
|
+
# (== 'pea y))) ;; => ((split pea))
|
640
|
+
result = instance.run
|
641
|
+
expect(result.car.car).to eq(split)
|
642
|
+
expect(result.car.cdr.car).to eq(pea)
|
643
|
+
end
|
644
|
+
|
645
|
+
it 'should allow simplication of expressions' do
|
646
|
+
expr1 = equals_goal(split, ref_x)
|
647
|
+
expr2 = equals_goal(pea, ref_y)
|
648
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
649
|
+
expr3 = equals_goal(red, ref_x)
|
650
|
+
expr4 = equals_goal(bean, ref_y)
|
651
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
652
|
+
goal = disj2_goal(subgoal1, subgoal2)
|
653
|
+
instance = RunStarExpression.new(%w[x y], goal)
|
654
|
+
|
655
|
+
# Reasoned S2, frame 1:76
|
656
|
+
# (run* (x y)
|
657
|
+
# (disj2
|
658
|
+
# (conj2 (== 'split x) (== 'pea y))
|
659
|
+
# (conj2 (== 'red x) (== 'bean y)))) ;; => ((split pea)(red bean))
|
660
|
+
result = instance.run
|
661
|
+
expect(result.car.car).to eq(split)
|
662
|
+
expect(result.car.cdr.car).to eq(pea)
|
663
|
+
expect(result.cdr.car.car).to eq(red)
|
664
|
+
expect(result.cdr.car.cdr.car).to eq(bean)
|
665
|
+
end
|
666
|
+
|
667
|
+
it 'should allow nesting a disjunction inside of conjunction' do
|
668
|
+
expr1 = equals_goal(split, ref_x)
|
669
|
+
expr2 = equals_goal(red, ref_x)
|
670
|
+
subgoal1 = disj2_goal(expr1, expr2)
|
671
|
+
subgoal2 = equals_goal(ref_x, ref_y)
|
672
|
+
goal = conj2_goal(subgoal1, subgoal2)
|
673
|
+
instance = RunStarExpression.new(%w[x y], goal)
|
674
|
+
|
675
|
+
# (display (run* (x y)
|
676
|
+
# (conj2
|
677
|
+
# (disj2
|
678
|
+
# (== 'split x)
|
679
|
+
# (== 'red x))
|
680
|
+
# (== x y)))) ;; => ((split split) (red red))
|
681
|
+
result = instance.run
|
682
|
+
expect(result.car.car).to eq(split)
|
683
|
+
expect(result.car.cdr.car).to eq(split)
|
684
|
+
expect(result.cdr.car.cdr.car).to eq(red)
|
685
|
+
end
|
686
|
+
|
687
|
+
it 'should accept fresh with multiple variables' do
|
688
|
+
expr1 = equals_goal(split, ref_x)
|
689
|
+
expr2 = equals_goal(pea, ref_y)
|
690
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
691
|
+
expr3 = equals_goal(red, ref_x)
|
692
|
+
expr4 = equals_goal(bean, ref_y)
|
693
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
694
|
+
subgoal3 = disj2_goal(subgoal1, subgoal2)
|
695
|
+
subgoal4 = equals_goal(cons(ref_x, cons(ref_y, cons(soup))), ref_r)
|
696
|
+
goal = conj2_goal(subgoal3, subgoal4)
|
697
|
+
fresh_env = FreshEnv.new(%w[x y], goal)
|
698
|
+
instance = RunStarExpression.new('r', fresh_env)
|
699
|
+
|
700
|
+
# Reasoned S2, frame 1:77
|
701
|
+
# (run* r
|
702
|
+
# (fresh (x y)
|
703
|
+
# (conj2
|
704
|
+
# (disj2
|
705
|
+
# (conj2 (== 'split x) (== 'pea y))
|
706
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
707
|
+
# (== '(,x ,y soup) r)))) ;; => ((split pea soup) (red bean soup))
|
708
|
+
result = instance.run
|
709
|
+
expect(result.car.car).to eq(split)
|
710
|
+
expect(result.car.cdr.car).to eq(pea)
|
711
|
+
expect(result.car.cdr.cdr.car).to eq(soup)
|
712
|
+
expect(result.cdr.car.car).to eq(red)
|
713
|
+
expect(result.cdr.car.cdr.car).to eq(bean)
|
714
|
+
expect(result.cdr.car.cdr.cdr.car).to eq(soup)
|
715
|
+
end
|
716
|
+
|
717
|
+
it 'should allow fresh with multiple goals' do
|
718
|
+
expr1 = equals_goal(split, ref_x)
|
719
|
+
expr2 = equals_goal(pea, ref_y)
|
720
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
721
|
+
expr3 = equals_goal(red, ref_x)
|
722
|
+
expr4 = equals_goal(bean, ref_y)
|
723
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
724
|
+
goal1 = disj2_goal(subgoal1, subgoal2)
|
725
|
+
goal2 = equals_goal(cons(ref_x, cons(ref_y, cons(soup))), ref_r)
|
726
|
+
fresh_env = FreshEnv.new(%w[x y], [goal1, goal2])
|
727
|
+
instance = RunStarExpression.new('r', fresh_env)
|
728
|
+
|
729
|
+
# Reasoned S2, frame 1:78
|
730
|
+
# (run* r
|
731
|
+
# (fresh (x y)
|
732
|
+
# (disj2
|
733
|
+
# (conj2 (== 'split x) (== 'pea y))
|
734
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
735
|
+
# (== '(,x ,y soup) r))) ;; => ((split pea soup) (red bean soup))
|
736
|
+
result = instance.run
|
737
|
+
expect(result.car.car).to eq(split)
|
738
|
+
expect(result.car.cdr.car).to eq(pea)
|
739
|
+
expect(result.car.cdr.cdr.car).to eq(soup)
|
740
|
+
expect(result.cdr.car.car).to eq(red)
|
741
|
+
expect(result.cdr.car.cdr.car).to eq(bean)
|
742
|
+
expect(result.cdr.car.cdr.cdr.car).to eq(soup)
|
743
|
+
end
|
744
|
+
|
745
|
+
it 'should allow run* with multiple goals' do
|
746
|
+
expr1 = equals_goal(split, ref_x)
|
747
|
+
expr2 = equals_goal(pea, ref_y)
|
748
|
+
subgoal1 = conj2_goal(expr1, expr2)
|
749
|
+
expr3 = equals_goal(red, ref_x)
|
750
|
+
expr4 = equals_goal(bean, ref_y)
|
751
|
+
subgoal2 = conj2_goal(expr3, expr4)
|
752
|
+
goal1 = disj2_goal(subgoal1, subgoal2)
|
753
|
+
goal2 = equals_goal(soup, ref_z)
|
754
|
+
instance = RunStarExpression.new(%w[x y z], [goal1, goal2])
|
755
|
+
|
756
|
+
# Reasoned S2, frame 1:80
|
757
|
+
# (run* (x y z)
|
758
|
+
# (disj2
|
759
|
+
# (conj2 (== 'split x) (== 'pea y))
|
760
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
761
|
+
# (== 'soup z)) ;; => ((split pea soup) (red bean soup))
|
762
|
+
result = instance.run
|
763
|
+
expect(result.car.car).to eq(split)
|
764
|
+
expect(result.car.cdr.car).to eq(pea)
|
765
|
+
expect(result.car.cdr.cdr.car).to eq(soup)
|
766
|
+
expect(result.cdr.car.car).to eq(red)
|
767
|
+
expect(result.cdr.car.cdr.car).to eq(bean)
|
768
|
+
expect(result.cdr.car.cdr.cdr.car).to eq(soup)
|
769
|
+
end
|
770
|
+
|
771
|
+
it 'should allow simplified expressions with multiple goals' do
|
772
|
+
expr1 = equals_goal(split, ref_x)
|
773
|
+
expr2 = equals_goal(pea, ref_y)
|
774
|
+
instance = RunStarExpression.new(%w[x y], [expr1, expr2])
|
775
|
+
|
776
|
+
# Reasoned S2, frame 1:81
|
777
|
+
# (run* (x y)
|
778
|
+
# (== 'split x)
|
779
|
+
# (== 'pea y)) ;; => ((split pea))
|
780
|
+
result = instance.run
|
781
|
+
expect(result.car.car).to eq(split)
|
782
|
+
expect(result.car.cdr.car).to eq(pea)
|
783
|
+
end
|
359
784
|
end # context
|
360
785
|
end # describe
|
361
786
|
end # module
|