mini_kraken 0.1.08 → 0.1.13
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/CHANGELOG.md +52 -0
- data/README.md +11 -3
- data/lib/mini_kraken/core/association_walker.rb +1 -1
- data/lib/mini_kraken/core/base_arg.rb +10 -0
- data/lib/mini_kraken/core/conde.rb +143 -0
- data/lib/mini_kraken/core/conj2.rb +5 -3
- data/lib/mini_kraken/core/def_relation.rb +49 -0
- data/lib/mini_kraken/core/disj2.rb +1 -0
- data/lib/mini_kraken/core/equals.rb +17 -13
- data/lib/mini_kraken/core/formal_arg.rb +22 -0
- data/lib/mini_kraken/core/formal_ref.rb +24 -0
- data/lib/mini_kraken/core/goal.rb +9 -3
- data/lib/mini_kraken/core/goal_arg.rb +5 -3
- data/lib/mini_kraken/core/goal_template.rb +60 -0
- data/lib/mini_kraken/core/k_boolean.rb +31 -0
- data/lib/mini_kraken/core/outcome.rb +14 -0
- data/lib/mini_kraken/core/relation.rb +7 -0
- data/lib/mini_kraken/core/variable.rb +10 -4
- data/lib/mini_kraken/core/vocabulary.rb +18 -1
- data/lib/mini_kraken/glue/fresh_env.rb +45 -3
- data/lib/mini_kraken/glue/run_star_expression.rb +43 -26
- data/lib/mini_kraken/version.rb +1 -1
- data/spec/core/conde_spec.rb +147 -0
- data/spec/core/def_relation_spec.rb +96 -0
- data/spec/core/equals_spec.rb +3 -3
- data/spec/core/goal_template_spec.rb +74 -0
- data/spec/core/k_boolean_spec.rb +107 -0
- data/spec/core/outcome_spec.rb +48 -0
- data/spec/core/vocabulary_spec.rb +6 -0
- data/spec/glue/fresh_env_spec.rb +27 -1
- data/spec/glue/run_star_expression_spec.rb +500 -7
- data/spec/support/factory_methods.rb +15 -0
- metadata +19 -2
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/disj2'
|
5
|
+
require_relative '../../lib/mini_kraken/core/equals'
|
6
|
+
require_relative '../../lib/mini_kraken/core/formal_arg'
|
7
|
+
require_relative '../../lib/mini_kraken/core/formal_ref'
|
8
|
+
require_relative '../../lib/mini_kraken/core/goal'
|
9
|
+
require_relative '../../lib/mini_kraken/core/goal_template'
|
10
|
+
require_relative '../../lib/mini_kraken/core/k_symbol'
|
11
|
+
require_relative '../../lib/mini_kraken/core/variable_ref'
|
12
|
+
require_relative '../../lib/mini_kraken/core/environment'
|
13
|
+
|
14
|
+
# Load the class under test
|
15
|
+
require_relative '../../lib/mini_kraken/core/def_relation'
|
16
|
+
|
17
|
+
module MiniKraken
|
18
|
+
module Core
|
19
|
+
describe DefRelation do
|
20
|
+
let(:tea) { KSymbol.new(:tea) }
|
21
|
+
let(:formal_t) { FormalArg.new('t') }
|
22
|
+
let(:t_ref) { FormalRef.new('t') }
|
23
|
+
let(:equals_tea) { GoalTemplate.new(Equals.instance, [tea, t_ref]) }
|
24
|
+
subject { DefRelation.new('teao', equals_tea, [formal_t]) }
|
25
|
+
|
26
|
+
context 'Initialization:' do
|
27
|
+
it 'should be initialized with a name, a goal template, formal args' do
|
28
|
+
expect { DefRelation.new('teao', equals_tea, [formal_t]) }.not_to raise_error
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should know its name' do
|
32
|
+
expect(subject.name).to eq('teao')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should know its goal template' do
|
36
|
+
expect(subject.goal_template).to eq(equals_tea)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should know its formals' do
|
40
|
+
expect(subject.formals).to eq([formal_t])
|
41
|
+
end
|
42
|
+
end # context
|
43
|
+
|
44
|
+
context 'Provided services:' do
|
45
|
+
let(:cup) { KSymbol.new(:cup) }
|
46
|
+
let(:ref_x) { VariableRef.new('x') }
|
47
|
+
let(:equals_cup) { GoalTemplate.new(Equals.instance, [cup, t_ref]) }
|
48
|
+
let(:g_template) { GoalTemplate.new(Disj2.instance, [equals_tea, equals_cup]) }
|
49
|
+
subject { DefRelation.new('teacup', g_template, [formal_t]) }
|
50
|
+
let(:env) { Environment.new }
|
51
|
+
|
52
|
+
it 'should provide solver for a single-node goal without var ref' do
|
53
|
+
defrel = DefRelation.new('teao', equals_tea, [formal_t])
|
54
|
+
solver = defrel.solver_for([tea], env)
|
55
|
+
outcome = solver.resume
|
56
|
+
expect(outcome).to be_successful
|
57
|
+
outcome = solver.resume
|
58
|
+
expect(outcome).to be_nil
|
59
|
+
|
60
|
+
solver = defrel.solver_for([cup], env)
|
61
|
+
outcome = solver.resume
|
62
|
+
expect(outcome).not_to be_successful
|
63
|
+
outcome = solver.resume
|
64
|
+
expect(outcome).to be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should provide solver for a single-node goal' do
|
68
|
+
defrel = DefRelation.new('teao', equals_tea, [formal_t])
|
69
|
+
env.add_var(Variable.new('x'))
|
70
|
+
solver = defrel.solver_for([ref_x], env)
|
71
|
+
outcome = solver.resume
|
72
|
+
expect(outcome).to be_successful
|
73
|
+
expect(ref_x.value(outcome)).to eq(tea)
|
74
|
+
|
75
|
+
outcome = solver.resume
|
76
|
+
expect(outcome).to be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should provide solver for a single-node goal' do
|
80
|
+
env.add_var(Variable.new('x'))
|
81
|
+
solver = subject.solver_for([ref_x], env)
|
82
|
+
outcome = solver.resume
|
83
|
+
expect(outcome).to be_successful
|
84
|
+
expect(ref_x.value(outcome)).to eq(tea)
|
85
|
+
|
86
|
+
outcome = solver.resume
|
87
|
+
expect(outcome).to be_successful
|
88
|
+
expect(ref_x.value(outcome)).to eq(cup)
|
89
|
+
|
90
|
+
outcome = solver.resume
|
91
|
+
expect(outcome).to be_nil
|
92
|
+
end
|
93
|
+
end # context
|
94
|
+
end # describe
|
95
|
+
end # module
|
96
|
+
end # module
|
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,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/disj2'
|
5
|
+
require_relative '../../lib/mini_kraken/core/equals'
|
6
|
+
require_relative '../../lib/mini_kraken/core/formal_arg'
|
7
|
+
require_relative '../../lib/mini_kraken/core/formal_ref'
|
8
|
+
require_relative '../../lib/mini_kraken/core/goal'
|
9
|
+
require_relative '../../lib/mini_kraken/core/k_symbol'
|
10
|
+
require_relative '../../lib/mini_kraken/core/variable_ref'
|
11
|
+
# require_relative '../../lib/mini_kraken/core/environment'
|
12
|
+
|
13
|
+
# Load the class under test
|
14
|
+
require_relative '../../lib/mini_kraken/core/goal_template'
|
15
|
+
|
16
|
+
|
17
|
+
module MiniKraken
|
18
|
+
module Core
|
19
|
+
describe GoalTemplate do
|
20
|
+
let(:tea) { KSymbol.new(:tea) }
|
21
|
+
let(:t_ref) { FormalRef.new('t') }
|
22
|
+
subject { GoalTemplate.new(Equals.instance, [tea, t_ref]) }
|
23
|
+
|
24
|
+
context 'Initialization:' do
|
25
|
+
it 'should be initialized with a relation and args' do
|
26
|
+
expect { GoalTemplate.new(Equals.instance, [tea, t_ref]) }.not_to raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should know its relation' do
|
30
|
+
expect(subject.relation).to eq(Equals.instance)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should know its arguments' do
|
34
|
+
expect(subject.args[0]).to eq(tea)
|
35
|
+
expect(subject.args[1]).to eq(t_ref)
|
36
|
+
end
|
37
|
+
end # context
|
38
|
+
|
39
|
+
context 'Provided services:' do
|
40
|
+
let(:formal_t) { FormalArg.new('t') }
|
41
|
+
let(:cup) { KSymbol.new(:cup) }
|
42
|
+
let(:ref_x) { VariableRef.new('x') }
|
43
|
+
# let(:env) { Environment.new }
|
44
|
+
|
45
|
+
it 'should instantiate a single-node goal' do
|
46
|
+
expect(subject.instantiate([formal_t], [cup])).to be_kind_of(Goal)
|
47
|
+
goal = subject.instantiate([formal_t], [cup])
|
48
|
+
expect(goal.relation).to eq(Equals.instance)
|
49
|
+
expect(goal.actuals[0]).to eq(tea)
|
50
|
+
expect(goal.actuals[1]).to eq(cup)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should instantiate a multiple-nodes goal' do
|
54
|
+
sub_tmp1 = GoalTemplate.new(Equals.instance, [tea, t_ref])
|
55
|
+
sub_tmp2 = GoalTemplate.new(Equals.instance, [cup, t_ref])
|
56
|
+
template = GoalTemplate.new(Disj2.instance, [sub_tmp1, sub_tmp2])
|
57
|
+
|
58
|
+
goal = template.instantiate([formal_t], [ref_x])
|
59
|
+
expect(goal.relation).to eq(Disj2.instance)
|
60
|
+
subgoal1 = goal.actuals[0]
|
61
|
+
expect(subgoal1).to be_kind_of(Goal)
|
62
|
+
expect(subgoal1.relation).to eq(Equals.instance)
|
63
|
+
expect(subgoal1.actuals[0]).to eq(tea)
|
64
|
+
expect(subgoal1.actuals[1]).to eq(ref_x)
|
65
|
+
subgoal2 = goal.actuals[1]
|
66
|
+
expect(subgoal2).to be_kind_of(Goal)
|
67
|
+
expect(subgoal2.relation).to eq(Equals.instance)
|
68
|
+
expect(subgoal2.actuals[0]).to eq(cup)
|
69
|
+
expect(subgoal2.actuals[1]).to eq(ref_x)
|
70
|
+
end
|
71
|
+
end # context
|
72
|
+
end # describe
|
73
|
+
end # module
|
74
|
+
end # module
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
# Load the class under test
|
7
|
+
require_relative '../../lib/mini_kraken/core/k_boolean'
|
8
|
+
|
9
|
+
module MiniKraken
|
10
|
+
module Core
|
11
|
+
describe KBoolean do
|
12
|
+
subject { KBoolean.new('#t') }
|
13
|
+
|
14
|
+
context 'Initialization:' do
|
15
|
+
it 'could be created with a Ruby true/false value' do
|
16
|
+
expect { KBoolean.new(true) }.not_to raise_error
|
17
|
+
expect { KBoolean.new(false) }.not_to raise_error
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'could be created with a Ruby Symbol value' do
|
21
|
+
expect { KBoolean.new(:"#t") }.not_to raise_error
|
22
|
+
expect { KBoolean.new(:"#f") }.not_to raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'could be created with a Ruby String value' do
|
26
|
+
expect { KBoolean.new('#t') }.not_to raise_error
|
27
|
+
expect { KBoolean.new('#f') }.not_to raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should know its value' do
|
31
|
+
expect(subject.value).to eq(true)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should know that it is a ground term' do
|
35
|
+
env = double('mock-env')
|
36
|
+
expect(subject.ground?(env)).to be_truthy
|
37
|
+
end
|
38
|
+
end # context
|
39
|
+
|
40
|
+
context 'Provided services:' do
|
41
|
+
it 'should know whether it is equal to another instance' do
|
42
|
+
# Same type, same value
|
43
|
+
other = KBoolean.new(true)
|
44
|
+
expect(subject).to be_eql(other)
|
45
|
+
|
46
|
+
other = KBoolean.new(:"#t")
|
47
|
+
expect(subject).to be_eql(other)
|
48
|
+
|
49
|
+
other = KBoolean.new('#t')
|
50
|
+
expect(subject).to be_eql(other)
|
51
|
+
|
52
|
+
# Same type, other value
|
53
|
+
another = KBoolean.new(false)
|
54
|
+
expect(subject).not_to be_eql(another)
|
55
|
+
|
56
|
+
# Same type, other value
|
57
|
+
another = KBoolean.new(:"#f")
|
58
|
+
expect(subject).not_to be_eql(another)
|
59
|
+
|
60
|
+
# Same type, other value
|
61
|
+
another = KBoolean.new('#f')
|
62
|
+
expect(subject).not_to be_eql(another)
|
63
|
+
|
64
|
+
# Different type, same value
|
65
|
+
yet_another = OpenStruct.new(value: true)
|
66
|
+
expect(subject).not_to be_eql(yet_another)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should know whether it has same value than other object' do
|
70
|
+
# Same type, same value
|
71
|
+
other = KBoolean.new(true)
|
72
|
+
expect(subject == other).to be_truthy
|
73
|
+
|
74
|
+
other = KBoolean.new(:"#t")
|
75
|
+
expect(subject == other).to be_truthy
|
76
|
+
|
77
|
+
other = KBoolean.new('#t')
|
78
|
+
expect(subject == other).to be_truthy
|
79
|
+
|
80
|
+
# Same type, other value
|
81
|
+
another = KBoolean.new(false)
|
82
|
+
expect(subject == another).to be_falsy
|
83
|
+
|
84
|
+
another = KBoolean.new(:"#f")
|
85
|
+
expect(subject == another).to be_falsy
|
86
|
+
|
87
|
+
another = KBoolean.new('#f')
|
88
|
+
expect(subject == another).to be_falsy
|
89
|
+
|
90
|
+
# Same duck type, same value
|
91
|
+
yet_another = OpenStruct.new(value: true)
|
92
|
+
expect(subject == yet_another).to be_truthy
|
93
|
+
|
94
|
+
# Different duck type, different value
|
95
|
+
still_another = OpenStruct.new(value: false)
|
96
|
+
expect(subject == still_another).to be_falsy
|
97
|
+
|
98
|
+
# Default Ruby representation, same value
|
99
|
+
expect(subject == true).to be_truthy
|
100
|
+
|
101
|
+
# Default Ruby representation, different value
|
102
|
+
expect(subject == false).to be_falsy
|
103
|
+
end
|
104
|
+
end # context
|
105
|
+
end # describe
|
106
|
+
end # module
|
107
|
+
end # module
|
@@ -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
|
@@ -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,10 +2,15 @@
|
|
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/conde'
|
5
6
|
require_relative '../../lib/mini_kraken/core/conj2'
|
7
|
+
require_relative '../../lib/mini_kraken/core/def_relation'
|
6
8
|
require_relative '../../lib/mini_kraken/core/disj2'
|
7
9
|
require_relative '../../lib/mini_kraken/core/equals'
|
8
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'
|
9
14
|
require_relative '../../lib/mini_kraken/core/succeed'
|
10
15
|
|
11
16
|
require_relative '../support/factory_methods'
|
@@ -21,16 +26,26 @@ module MiniKraken
|
|
21
26
|
let(:pea) { k_symbol(:pea) }
|
22
27
|
let(:pod) { k_symbol(:pod) }
|
23
28
|
let(:sample_goal) { equals_goal(pea, pod) }
|
29
|
+
let(:fails) { Core::Goal.new(Core::Fail.instance, []) }
|
30
|
+
let(:succeeds) { Core::Goal.new(Core::Succeed.instance, []) }
|
24
31
|
subject { RunStarExpression.new('q', sample_goal) }
|
25
32
|
|
26
33
|
context 'Initialization:' do
|
27
|
-
it '
|
34
|
+
it 'could be initialized with a name and a goal' do
|
28
35
|
expect { RunStarExpression.new('q', sample_goal) }.not_to raise_error
|
29
36
|
end
|
30
37
|
|
38
|
+
it 'could be initialized with multiple names and a goal' do
|
39
|
+
expect { RunStarExpression.new(%w[r x y], sample_goal) }.not_to raise_error
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'could be initialized with multiple names and goals' do
|
43
|
+
expect { RunStarExpression.new(%w[r x y], [succeeds, succeeds]) }.not_to raise_error
|
44
|
+
end
|
45
|
+
|
31
46
|
it 'should know its variables' do
|
32
47
|
expect(subject.env.vars['q']).not_to be_nil
|
33
|
-
expect(subject.
|
48
|
+
expect(subject.env.vars.values[0].name).to eq('q')
|
34
49
|
end
|
35
50
|
|
36
51
|
it 'should know its goal' do
|
@@ -39,19 +54,40 @@ module MiniKraken
|
|
39
54
|
end # context
|
40
55
|
|
41
56
|
context 'Provided services:' do
|
57
|
+
let(:k_false) { k_boolean(false) }
|
58
|
+
let(:k_true) { k_boolean(true) }
|
59
|
+
let(:bean) { k_symbol(:bean) }
|
42
60
|
let(:corn) { k_symbol(:corn) }
|
61
|
+
let(:cup) { k_symbol(:cup) }
|
62
|
+
let(:green) { k_symbol(:green) }
|
63
|
+
let(:lentil) { k_symbol(:lentil) }
|
43
64
|
let(:meal) { k_symbol(:meal) }
|
44
65
|
let(:oil) { k_symbol(:oil) }
|
45
66
|
let(:olive) { k_symbol(:olive) }
|
67
|
+
let(:red) { k_symbol(:red) }
|
68
|
+
let(:soup) { k_symbol(:soup) }
|
69
|
+
let(:split) { k_symbol(:split) }
|
70
|
+
let(:tea) { k_symbol(:tea) }
|
46
71
|
let(:virgin) { k_symbol(:virgin) }
|
47
72
|
let(:ref_q) { Core::VariableRef.new('q') }
|
73
|
+
let(:ref_r) { Core::VariableRef.new('r') }
|
48
74
|
let(:ref_x) { Core::VariableRef.new('x') }
|
49
75
|
let(:ref_y) { Core::VariableRef.new('y') }
|
76
|
+
let(:ref_z) { Core::VariableRef.new('z') }
|
50
77
|
let(:ref_s) { Core::VariableRef.new('s') }
|
51
78
|
let(:ref_t) { Core::VariableRef.new('t') }
|
52
79
|
let(:ref_u) { Core::VariableRef.new('u') }
|
53
|
-
let(:
|
54
|
-
let(:
|
80
|
+
let(:ref_z) { Core::VariableRef.new('z') }
|
81
|
+
let(:t_ref) { Core::FormalRef.new('t') }
|
82
|
+
let(:equals_tea) { Core::GoalTemplate.new(Core::Equals.instance, [tea, t_ref]) }
|
83
|
+
let(:equals_cup) { Core::GoalTemplate.new(Core::Equals.instance, [cup, t_ref]) }
|
84
|
+
let(:g_template) { Core::GoalTemplate.new(Core::Disj2.instance, [equals_tea, equals_cup]) }
|
85
|
+
let(:formal_t) { Core::FormalArg.new('t') }
|
86
|
+
|
87
|
+
# Reasoned S2, frame 1:82
|
88
|
+
# (defrel (teacupo t)
|
89
|
+
# (disj2 (== 'tea t) (== 'cup t)))
|
90
|
+
let(:teacupo_rel) { Core::DefRelation.new('teacupo', g_template, [formal_t]) }
|
55
91
|
|
56
92
|
it 'should return a null list with the fail goal' do
|
57
93
|
# Reasoned S2, frame 1:7
|
@@ -90,6 +126,7 @@ module MiniKraken
|
|
90
126
|
|
91
127
|
it 'should return a null list with the succeed goal' do
|
92
128
|
instance = RunStarExpression.new('q', succeeds)
|
129
|
+
expect(instance.env.vars).to be_include('q')
|
93
130
|
|
94
131
|
# (display (run* q succeed)) ;; => (_0)
|
95
132
|
# Reasoned S2, frame 1:16
|
@@ -386,7 +423,7 @@ module MiniKraken
|
|
386
423
|
instance = RunStarExpression.new('q', goal)
|
387
424
|
|
388
425
|
# Reasoned S2, frame 1:56
|
389
|
-
# (run* q (disj2 (
|
426
|
+
# (run* q (disj2 (== 'olive q) fail)) ;; => ('olive)
|
390
427
|
result = instance.run
|
391
428
|
expect(result.car).to eq(olive)
|
392
429
|
end
|
@@ -397,7 +434,7 @@ module MiniKraken
|
|
397
434
|
instance = RunStarExpression.new('q', goal)
|
398
435
|
|
399
436
|
# Reasoned S2, frame 1:57
|
400
|
-
# (run* q (disj2 fail (
|
437
|
+
# (run* q (disj2 fail (== 'oil q))) ;; => (oil)
|
401
438
|
result = instance.run
|
402
439
|
expect(result.car).to eq(oil)
|
403
440
|
end
|
@@ -409,7 +446,7 @@ module MiniKraken
|
|
409
446
|
instance = RunStarExpression.new('q', goal)
|
410
447
|
|
411
448
|
# Reasoned S2, frame 1:58
|
412
|
-
# (run* q (disj2 (
|
449
|
+
# (run* q (disj2 (== 'olive q) (== 'oil q))) ;; => (olive oil)
|
413
450
|
result = instance.run
|
414
451
|
expect(result.car).to eq(olive)
|
415
452
|
expect(result.cdr.car).to eq(oil)
|
@@ -504,6 +541,462 @@ module MiniKraken
|
|
504
541
|
expect(result.cdr.car).to eq(any_value(0))
|
505
542
|
expect(result.cdr.cdr.car).to eq(oil)
|
506
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 simplication 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
|
507
1000
|
end # context
|
508
1001
|
end # describe
|
509
1002
|
end # module
|