mini_kraken 0.1.01 → 0.1.02
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 +3 -0
- data/README.md +0 -3
- data/lib/mini_kraken/core/any_value.rb +29 -0
- data/lib/mini_kraken/core/association.rb +21 -0
- data/lib/mini_kraken/core/association_walker.rb +179 -0
- data/lib/mini_kraken/core/atomic_term.rb +64 -0
- data/lib/mini_kraken/core/binary_relation.rb +61 -0
- data/lib/mini_kraken/core/composite_term.rb +54 -0
- data/lib/mini_kraken/core/cons_cell.rb +44 -0
- data/lib/mini_kraken/core/duck_fiber.rb +44 -0
- data/lib/mini_kraken/core/environment.rb +59 -0
- data/lib/mini_kraken/core/equals.rb +216 -0
- data/lib/mini_kraken/core/fail.rb +8 -5
- data/lib/mini_kraken/core/freshness.rb +42 -0
- data/lib/mini_kraken/core/goal.rb +31 -6
- data/lib/mini_kraken/core/k_integer.rb +15 -0
- data/lib/mini_kraken/core/k_symbol.rb +15 -0
- data/lib/mini_kraken/core/nullary_relation.rb +11 -3
- data/lib/mini_kraken/core/outcome.rb +35 -0
- data/lib/mini_kraken/core/relation.rb +31 -4
- data/lib/mini_kraken/core/succeed.rb +13 -1
- data/lib/mini_kraken/core/term.rb +7 -0
- data/lib/mini_kraken/core/variable.rb +45 -3
- data/lib/mini_kraken/core/variable_ref.rb +76 -0
- data/lib/mini_kraken/core/vocabulary.rb +161 -0
- data/lib/mini_kraken/glue/fresh_env.rb +31 -0
- data/lib/mini_kraken/glue/run_star_expression.rb +43 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/spec/core/association_spec.rb +38 -0
- data/spec/core/association_walker_spec.rb +191 -0
- data/spec/core/cons_cell_spec.rb +63 -0
- data/spec/core/duck_fiber_spec.rb +62 -0
- data/spec/core/environment_spec.rb +154 -0
- data/spec/core/equals_spec.rb +289 -0
- data/spec/core/fail_spec.rb +16 -0
- data/spec/core/goal_spec.rb +36 -10
- data/spec/core/k_symbol_spec.rb +72 -0
- data/spec/core/succeed_spec.rb +43 -0
- data/spec/core/variable_ref_spec.rb +31 -0
- data/spec/core/variable_spec.rb +11 -3
- data/spec/core/vocabulary_spec.rb +188 -0
- data/spec/glue/fresh_env_spec.rb +36 -0
- data/spec/glue/run_star_expression_spec.rb +247 -0
- data/spec/support/factory_methods.rb +54 -0
- metadata +46 -13
- data/lib/mini_kraken/core/facade.rb +0 -45
- data/lib/mini_kraken/core/formal_arg.rb +0 -6
- data/lib/mini_kraken/core/publisher.rb +0 -27
- data/lib/mini_kraken/core/run_star_expression.rb +0 -34
- data/lib/mini_kraken/dsl/kraken_dsl.rb +0 -12
- data/spec/core/facade_spec.rb +0 -38
- data/spec/core/run_star_expression_spec.rb +0 -43
- data/spec/dsl/kraken_dsl_spec.rb +0 -31
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/mini_kraken/core/succeed'
|
7
|
+
|
8
|
+
module MiniKraken
|
9
|
+
module Core
|
10
|
+
describe Succeed do
|
11
|
+
subject { Succeed.instance }
|
12
|
+
|
13
|
+
context 'Initialization:' do
|
14
|
+
it 'should have one instance' do
|
15
|
+
expect { Succeed.instance }.not_to raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should know its name' do
|
19
|
+
expect(subject.name).to eq('succeed')
|
20
|
+
end
|
21
|
+
end # context
|
22
|
+
|
23
|
+
context 'Provided services:' do
|
24
|
+
it 'should unconditionally return a success result' do
|
25
|
+
args = double('fake-args')
|
26
|
+
env = double('fake-env')
|
27
|
+
|
28
|
+
solver = nil
|
29
|
+
expect { solver = subject.solver_for(args, env) }.not_to raise_error
|
30
|
+
|
31
|
+
# Solver should quack like a Fiber
|
32
|
+
dummy_arg = double('dummy-stuff')
|
33
|
+
result = solver.resume(dummy_arg)
|
34
|
+
expect(result).to eq(BasicSuccess)
|
35
|
+
|
36
|
+
# Only one "solution", next 'resume' call should return nil
|
37
|
+
result = solver.resume(dummy_arg)
|
38
|
+
expect(result).to be_nil
|
39
|
+
end
|
40
|
+
end # context
|
41
|
+
end # describe
|
42
|
+
end # module
|
43
|
+
end # module
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/mini_kraken/core/variable_ref'
|
7
|
+
|
8
|
+
module MiniKraken
|
9
|
+
module Core
|
10
|
+
describe VariableRef do
|
11
|
+
subject { VariableRef.new('q') }
|
12
|
+
|
13
|
+
context 'Initialization:' do
|
14
|
+
it 'should be initialized with the name of variable' do
|
15
|
+
expect { VariableRef.new('q') }.not_to raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should know the name of a variable' do
|
19
|
+
expect(subject.var_name).to eq('q')
|
20
|
+
end
|
21
|
+
|
22
|
+
# it 'should be fresh by default' do
|
23
|
+
# expect(subject).to be_fresh
|
24
|
+
# end
|
25
|
+
end # context
|
26
|
+
|
27
|
+
context 'Provided services:' do
|
28
|
+
end # context
|
29
|
+
end # describe
|
30
|
+
end # module
|
31
|
+
end # module
|
data/spec/core/variable_spec.rb
CHANGED
@@ -1,27 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/environment'
|
4
5
|
|
5
6
|
# Load the class under test
|
6
|
-
require_relative '../../lib/mini_kraken/core/variable'
|
7
|
+
require_relative '../../lib/mini_kraken/core/variable'
|
8
|
+
|
7
9
|
|
8
10
|
module MiniKraken
|
9
11
|
module Core
|
10
12
|
describe Variable do
|
13
|
+
let(:env) { Environment.new }
|
11
14
|
subject { Variable.new('q') }
|
12
15
|
|
13
16
|
context 'Initialization:' do
|
14
17
|
it 'should be initialized with a name' do
|
15
18
|
expect { Variable.new('q') }.not_to raise_error
|
16
19
|
end
|
17
|
-
|
20
|
+
|
18
21
|
it 'should know its name' do
|
19
22
|
expect(subject.name).to eq('q')
|
20
23
|
end
|
24
|
+
|
25
|
+
it 'should be fresh by default' do
|
26
|
+
env.add_var(subject)
|
27
|
+
expect(subject.fresh?(env)).to be_truthy
|
28
|
+
end
|
21
29
|
end # context
|
22
30
|
|
23
31
|
context 'Provided services:' do
|
24
32
|
end # context
|
25
33
|
end # describe
|
26
34
|
end # module
|
27
|
-
end # module
|
35
|
+
end # module
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/association'
|
5
|
+
require_relative '../../lib/mini_kraken/core/k_symbol'
|
6
|
+
require_relative '../../lib/mini_kraken/core/variable_ref'
|
7
|
+
require_relative '../support/factory_methods'
|
8
|
+
|
9
|
+
# Load the class under test
|
10
|
+
require_relative '../../lib/mini_kraken/core/vocabulary'
|
11
|
+
|
12
|
+
|
13
|
+
module MiniKraken
|
14
|
+
module Core
|
15
|
+
|
16
|
+
class TestVocabulary
|
17
|
+
include Vocabulary
|
18
|
+
|
19
|
+
def initialize(aParent = nil)
|
20
|
+
init_vocabulary(aParent)
|
21
|
+
end
|
22
|
+
end # class
|
23
|
+
|
24
|
+
module VariableBearer
|
25
|
+
attr_reader :vars
|
26
|
+
|
27
|
+
def init_var_bearer
|
28
|
+
@vars = {}
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_var(aVarName)
|
33
|
+
vars[aVarName] = aVarName.hash # Just for testing purposes
|
34
|
+
end
|
35
|
+
end # module
|
36
|
+
|
37
|
+
describe Vocabulary do
|
38
|
+
include FactoryMethods
|
39
|
+
|
40
|
+
let(:parent) { TestVocabulary.new }
|
41
|
+
subject { TestVocabulary.new }
|
42
|
+
|
43
|
+
context 'Initialization:' do
|
44
|
+
it 'could be initialized without a parent' do
|
45
|
+
expect { TestVocabulary.new }.not_to raise_error
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'could be initialized with a parent' do
|
49
|
+
expect { TestVocabulary.new(parent) }.not_to raise_error
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should know its parent (if any)' do
|
53
|
+
expect(subject.parent).to be_nil
|
54
|
+
instance = TestVocabulary.new(parent)
|
55
|
+
expect(instance.parent).to eq(parent)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should have no associations at initialization' do
|
59
|
+
expect(subject.associations).to be_empty
|
60
|
+
end
|
61
|
+
end # context
|
62
|
+
|
63
|
+
context 'Provided services:' do
|
64
|
+
let(:pea) { KSymbol.new(:pea) }
|
65
|
+
let(:pod) { KSymbol.new(:pod) }
|
66
|
+
let(:ref_q) { VariableRef.new('q') }
|
67
|
+
let(:ref_x) { VariableRef.new('x') }
|
68
|
+
let(:grandma) do
|
69
|
+
voc = TestVocabulary.new
|
70
|
+
voc.extend(VariableBearer)
|
71
|
+
voc.init_var_bearer
|
72
|
+
end
|
73
|
+
let(:mother) { TestVocabulary.new(grandma) }
|
74
|
+
subject { TestVocabulary.new(mother) }
|
75
|
+
|
76
|
+
it 'should provide a walker over ancestors' do
|
77
|
+
walker = subject.ancestor_walker
|
78
|
+
expect(walker).to be_kind_of(Fiber)
|
79
|
+
expect(walker.resume).to eq(subject)
|
80
|
+
expect(walker.resume).to eq(mother)
|
81
|
+
expect(walker.resume).to eq(grandma)
|
82
|
+
expect(walker.resume).to be_nil
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should know if a variable is defined' do
|
86
|
+
expect(subject.include?('q')).to be_falsey
|
87
|
+
grandma.add_var('x')
|
88
|
+
expect(subject.include?('q')).to be_falsey
|
89
|
+
expect(grandma.include?('x')).to be_truthy
|
90
|
+
expect(mother.include?('x')).to be_truthy
|
91
|
+
expect(subject.include?('x')).to be_truthy
|
92
|
+
subject.extend(VariableBearer)
|
93
|
+
subject.init_var_bearer
|
94
|
+
subject.add_var('y')
|
95
|
+
expect(subject.include?('y')).to be_truthy
|
96
|
+
expect(mother.include?('y')).to be_falsey
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should allow the addition of associations' do
|
100
|
+
grandma.add_var('q')
|
101
|
+
expect(subject['q']).to be_empty
|
102
|
+
mother.add_assoc(Association.new('q', pea))
|
103
|
+
expect(subject['q'].size).to eq(1)
|
104
|
+
expect(subject['q'].first.value).to eq(pea)
|
105
|
+
|
106
|
+
subject.add_assoc(Association.new('q', ref_x))
|
107
|
+
expect(subject['q'].size).to eq(2)
|
108
|
+
expect(subject['q'].first.value).to eq(ref_x)
|
109
|
+
expect(subject['q'].last.value).to eq(pea)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should allow the deletion of associations' do
|
113
|
+
grandma.add_var('q')
|
114
|
+
mother.add_assoc(Association.new('q', pea))
|
115
|
+
subject.add_assoc(Association.new('q', ref_x))
|
116
|
+
expect(mother.associations.size).to eq(1)
|
117
|
+
expect(subject.associations.size).to eq(1)
|
118
|
+
|
119
|
+
subject.clear
|
120
|
+
expect(subject.associations).to be_empty
|
121
|
+
|
122
|
+
mother.clear
|
123
|
+
expect(mother.associations).to be_empty
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should say fresh when a variable has no association at all' do
|
127
|
+
grandma.add_var('q')
|
128
|
+
grandma.add_var('x')
|
129
|
+
expect(subject.fresh?(ref_q)).to be_truthy
|
130
|
+
subject.add_assoc(Association.new('q', ref_x)) # Dependency: q --> x
|
131
|
+
expect(subject.fresh?(ref_x)).to be_truthy
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should say not fresh when variable --> atomic value' do
|
135
|
+
grandma.add_var('q')
|
136
|
+
grandma.add_var('x')
|
137
|
+
subject.add_assoc(Association.new('q', ref_x)) # Dependency: q --> x
|
138
|
+
expect(subject.fresh?(ref_q)).to be_truthy
|
139
|
+
|
140
|
+
# Associate with an atomic term
|
141
|
+
subject.add_assoc(Association.new('q', pea))
|
142
|
+
expect(subject.fresh?(ref_q)).to be_falsey
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should say not fresh when variable --> composite of atomics' do
|
146
|
+
grandma.add_var('q')
|
147
|
+
|
148
|
+
# Composite having only atomic terms as leaf elements
|
149
|
+
expr = cons(pea, cons(pod))
|
150
|
+
subject.add_assoc(Association.new('q', expr))
|
151
|
+
expect(subject.fresh?(ref_q)).to be_falsey
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'say not fresh when variable --> composite of atomics & bound var' do
|
155
|
+
grandma.add_var('q')
|
156
|
+
grandma.add_var('x')
|
157
|
+
subject.add_assoc(Association.new('x', pea)) # Dependency: x --> pea
|
158
|
+
expr = cons(pea, cons(pod, cons(ref_x)))
|
159
|
+
subject.add_assoc(Association.new('q', expr))
|
160
|
+
expect(subject.fresh?(ref_q)).to be_falsey
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'say not fresh when variable --> composite of atomics & fresh var' do
|
164
|
+
grandma.add_var('q')
|
165
|
+
grandma.add_var('x')
|
166
|
+
expr = cons(pea, cons(pod, cons(ref_x)))
|
167
|
+
subject.add_assoc(Association.new('q', expr))
|
168
|
+
expect(subject.fresh?(ref_q)).to be_truthy
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'say not fresh when variables are fused & one is ground' do
|
172
|
+
grandma.add_var('q')
|
173
|
+
grandma.add_var('x')
|
174
|
+
|
175
|
+
# Beware of cyclic structure
|
176
|
+
subject.add_assoc(Association.new('q', ref_x)) # Dependency: q --> x
|
177
|
+
subject.add_assoc(Association.new('x', ref_q)) # Dependency: x --> q
|
178
|
+
expect(subject.fresh?(ref_x)).to be_truthy
|
179
|
+
expect(subject.fresh?(ref_q)).to be_truthy
|
180
|
+
|
181
|
+
# Associate with an atomic term
|
182
|
+
subject.add_assoc(Association.new('x', pea))
|
183
|
+
expect(subject.fresh?(ref_q)).to be_falsey
|
184
|
+
end
|
185
|
+
end # context
|
186
|
+
end # describe
|
187
|
+
end # module
|
188
|
+
end # module
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/goal'
|
5
|
+
require_relative '../../lib/mini_kraken/core/equals'
|
6
|
+
require_relative '../../lib/mini_kraken/core/k_symbol'
|
7
|
+
|
8
|
+
# Load the class under test
|
9
|
+
require_relative '../../lib/mini_kraken/glue/fresh_env'
|
10
|
+
|
11
|
+
|
12
|
+
module MiniKraken
|
13
|
+
module Glue
|
14
|
+
describe FreshEnv do
|
15
|
+
let(:pea) { Core::KSymbol.new(:pea) }
|
16
|
+
let(:pod) { Core::KSymbol.new(:pod) }
|
17
|
+
let(:sample_goal) do
|
18
|
+
Core::Goal.new(Core::Equals.instance, [pea, pod])
|
19
|
+
end
|
20
|
+
subject { FreshEnv.new(['q'], sample_goal) }
|
21
|
+
|
22
|
+
context 'Initialization:' do
|
23
|
+
it 'should be initialized with an array of names' do
|
24
|
+
expect { FreshEnv.new(['q'], sample_goal) }.not_to raise_error
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should know its variables' do
|
28
|
+
expect(subject.vars['q']).not_to be_nil
|
29
|
+
end
|
30
|
+
end # context
|
31
|
+
|
32
|
+
context 'Provided services:' do
|
33
|
+
end # context
|
34
|
+
end # describe
|
35
|
+
end # module
|
36
|
+
end # module
|
@@ -0,0 +1,247 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/goal'
|
5
|
+
require_relative '../../lib/mini_kraken/core/equals'
|
6
|
+
require_relative '../../lib/mini_kraken/core/fail'
|
7
|
+
require_relative '../../lib/mini_kraken/core/succeed'
|
8
|
+
|
9
|
+
require_relative '../support/factory_methods'
|
10
|
+
|
11
|
+
# Load the class under test
|
12
|
+
require_relative '../../lib/mini_kraken/glue/run_star_expression'
|
13
|
+
|
14
|
+
|
15
|
+
module MiniKraken
|
16
|
+
module Glue
|
17
|
+
describe RunStarExpression do
|
18
|
+
include FactoryMethods
|
19
|
+
let(:pea) { k_symbol(:pea) }
|
20
|
+
let(:pod) { k_symbol(:pod) }
|
21
|
+
let(:sample_goal) { equals_goal(pea, pod) }
|
22
|
+
subject { RunStarExpression.new('q', sample_goal) }
|
23
|
+
|
24
|
+
context 'Initialization:' do
|
25
|
+
it 'should be initialized with a name and a goal' do
|
26
|
+
expect { RunStarExpression.new('q', sample_goal) }.not_to raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should know its variables' do
|
30
|
+
expect(subject.env.vars['q']).not_to be_nil
|
31
|
+
expect(subject.var.name).to eq('q')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should know its goal' do
|
35
|
+
expect(subject.env.goal).to eq(sample_goal)
|
36
|
+
end
|
37
|
+
end # context
|
38
|
+
|
39
|
+
context 'Provided services:' do
|
40
|
+
let(:ref_q) { Core::VariableRef.new('q') }
|
41
|
+
let(:ref_x) { Core::VariableRef.new('x') }
|
42
|
+
|
43
|
+
it "should return a null list with the fail goal" do
|
44
|
+
# Reasoned S2, frame 1:7
|
45
|
+
# (run* q #u) ;; => ()
|
46
|
+
failing = Core::Goal.new(Core::Fail.instance, [])
|
47
|
+
instance = RunStarExpression.new('q', failing)
|
48
|
+
|
49
|
+
expect(instance.run).to be_null
|
50
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return a null list when a goal fails" do
|
54
|
+
# Reasoned S2, frame 1:10
|
55
|
+
# (run* q (== 'pea 'pod) ;; => ()
|
56
|
+
|
57
|
+
expect(subject.run).to be_null
|
58
|
+
expect(ref_q.fresh?(subject.env)).to be_truthy
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should unify the variable with the equals goal with symbol' do
|
62
|
+
goal = equals_goal(ref_q, pea)
|
63
|
+
instance = RunStarExpression.new('q', goal)
|
64
|
+
|
65
|
+
# Reasoned S2, frame 1:11
|
66
|
+
# (run* q (== q 'pea) ;; => (pea)
|
67
|
+
expect(instance.run.car).to eq(pea)
|
68
|
+
expect(ref_q.fresh?(instance.env)).to be_falsey
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should unify the righthand variable(s)' do
|
72
|
+
goal = equals_goal(pea, ref_q)
|
73
|
+
instance = RunStarExpression.new('q', goal)
|
74
|
+
|
75
|
+
# Reasoned S2, frame 1:12
|
76
|
+
# (run* q (== 'pea q) ;; => (pea)
|
77
|
+
expect(instance.run.car).to eq(pea)
|
78
|
+
|
79
|
+
# Reasoned S2, frame 1:15
|
80
|
+
expect(ref_q.fresh?(instance.env)).to be_falsey
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should return a null list with the succeed goal' do
|
84
|
+
success = Core::Goal.new(Core::Succeed.instance, [])
|
85
|
+
instance = RunStarExpression.new('q', success)
|
86
|
+
|
87
|
+
# (display (run* q succeed)) ;; => (_0)
|
88
|
+
# Reasoned S2, frame 1:16
|
89
|
+
result = instance.run
|
90
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy
|
91
|
+
|
92
|
+
# Reasoned S2, frame 1:17
|
93
|
+
expect(result.car).to eq(any_value(0))
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should keep variable fresh when no unification occurs (I)' do
|
97
|
+
goal = equals_goal(pea, pea)
|
98
|
+
instance = RunStarExpression.new('q', goal)
|
99
|
+
|
100
|
+
# (display (run* q (== 'pea 'pea))) ;; => (_0)
|
101
|
+
# Reasoned S2, frame 1:19
|
102
|
+
result = instance.run
|
103
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy
|
104
|
+
expect(result.car).to eq(any_value(0))
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should keep variable fresh when no unification occurs (III)' do
|
108
|
+
ref1_q = Core::VariableRef.new('q')
|
109
|
+
ref2_q = Core::VariableRef.new('q')
|
110
|
+
goal = equals_goal(ref1_q, ref2_q)
|
111
|
+
instance = RunStarExpression.new('q', goal)
|
112
|
+
|
113
|
+
# (display (run* q (== q q))) ;; => (_0)
|
114
|
+
# Reasoned S2, frame 1:20
|
115
|
+
result = instance.run
|
116
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy
|
117
|
+
expect(result.car).to eq(any_value(0))
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should accept the nesting of sub-environment' do
|
121
|
+
goal = equals_goal(pea, ref_q)
|
122
|
+
fresh_env = FreshEnv.new(['x'], goal)
|
123
|
+
instance = RunStarExpression.new('q', fresh_env)
|
124
|
+
|
125
|
+
# Reasoned S2, frame 1:21..23
|
126
|
+
# (run* q (fresh (x) (== 'pea q))) ;; => (pea)
|
127
|
+
result = instance.run
|
128
|
+
expect(ref_q.fresh?(instance.env)).to be_falsey
|
129
|
+
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
130
|
+
expect(result.car).to eq(pea)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should unify nested variables' do
|
134
|
+
goal = equals_goal(pea, ref_x)
|
135
|
+
fresh_env = FreshEnv.new(['x'], goal)
|
136
|
+
instance = RunStarExpression.new('q', fresh_env)
|
137
|
+
|
138
|
+
# Reasoned S2, frame 1:24
|
139
|
+
# (run* q (fresh (x) (== 'pea x))) ;; => (_0)
|
140
|
+
result = instance.run
|
141
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy
|
142
|
+
expect(ref_x.fresh?(fresh_env)).to be_falsey
|
143
|
+
expect(result.car).to eq(any_value(0))
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should accept expression with variables' do
|
147
|
+
goal = equals_goal(cons(ref_x), ref_q)
|
148
|
+
fresh_env = FreshEnv.new(['x'], goal)
|
149
|
+
instance = RunStarExpression.new('q', fresh_env)
|
150
|
+
|
151
|
+
# Reasoned S2, frame 1:25
|
152
|
+
# (run* q (fresh (x) (== (cons x '()) q))) ;; => ((_0))
|
153
|
+
result = instance.run
|
154
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy
|
155
|
+
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
156
|
+
expect(result.car).to eq(cons(any_value(0)))
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should accept fused variables' do
|
160
|
+
goal = equals_goal(ref_x, ref_q)
|
161
|
+
fresh_env = FreshEnv.new(['x'], goal)
|
162
|
+
instance = RunStarExpression.new('q', fresh_env)
|
163
|
+
|
164
|
+
# Reasoned S2, frame 1:31
|
165
|
+
# (run* q (fresh (x) (== x q))) ;; => (_0)
|
166
|
+
result = instance.run
|
167
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy
|
168
|
+
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
169
|
+
expect(result.car).to eq(any_value(0))
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'should cope with complex equality expressions' do
|
173
|
+
expr1 = cons(cons(cons(pea)), pod)
|
174
|
+
expr2 = cons(cons(cons(pea)), pod)
|
175
|
+
goal = equals_goal(expr1, expr2)
|
176
|
+
instance = RunStarExpression.new('q', goal)
|
177
|
+
|
178
|
+
# Reasoned S2, frame 1:32
|
179
|
+
# (run* q (== '(((pea)) pod) '(((pea)) pod))) ;; => (_0)
|
180
|
+
result = instance.run
|
181
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy
|
182
|
+
expect(result.car).to eq(any_value(0))
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should unify complex equality expressions (I)' do
|
186
|
+
expr1 = cons(cons(cons(pea)), pod)
|
187
|
+
expr2 = cons(cons(cons(pea)), ref_q)
|
188
|
+
goal = equals_goal(expr1, expr2)
|
189
|
+
instance = RunStarExpression.new('q', goal)
|
190
|
+
|
191
|
+
# Beware: quasiquoting
|
192
|
+
# Reasoned S2, frame 1:33
|
193
|
+
# (run* q (== '(((pea)) pod) `(((pea)) ,q))) ;; => ('pod)
|
194
|
+
result = instance.run
|
195
|
+
expect(ref_q.fresh?(instance.env)).to be_falsey
|
196
|
+
expect(result.car).to eq(pod)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should unify complex equality expressions (II)' do
|
200
|
+
expr1 = cons(cons(cons(ref_q)), pod)
|
201
|
+
expr2 = cons(cons(cons(pea)), pod)
|
202
|
+
goal = equals_goal(expr1, expr2)
|
203
|
+
instance = RunStarExpression.new('q', goal)
|
204
|
+
|
205
|
+
# Reasoned S2, frame 1:34
|
206
|
+
# (run* q (== '(((,q)) pod) `(((pea)) pod))) ;; => ('pod)
|
207
|
+
result = instance.run
|
208
|
+
expect(ref_q.fresh?(instance.env)).to be_falsey
|
209
|
+
expect(result.car).to eq(pea)
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should unify complex equality expressions (II)' do
|
213
|
+
expr1 = cons(cons(cons(ref_q)), pod)
|
214
|
+
expr2 = cons(cons(cons(ref_x)), pod)
|
215
|
+
goal = equals_goal(expr1, expr2)
|
216
|
+
fresh_env = FreshEnv.new(['x'], goal)
|
217
|
+
instance = RunStarExpression.new('q', fresh_env)
|
218
|
+
|
219
|
+
# Reasoned S2, frame 1:35
|
220
|
+
# (run* q (fresh (x) (== '(((,q)) pod) `(((,x)) pod)))) ;; => (_0)
|
221
|
+
result = instance.run
|
222
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy
|
223
|
+
expect(ref_x.fresh?(fresh_env)).to be_truthy
|
224
|
+
expect(result.car).to eq(any_value(0))
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'should unify complex equality expressions (II)' do
|
228
|
+
# # Reasoned S2, frame 1:36
|
229
|
+
# # (run* q (fresh (x) (== '(((,q)) (,x)) `(((,x)) pod)))) ;; => ('pod)
|
230
|
+
expr1 = cons(cons(cons(ref_q)), ref_x)
|
231
|
+
expr2 = cons(cons(cons(ref_x)), pod)
|
232
|
+
goal = equals_goal(expr1, expr2)
|
233
|
+
fresh_env = FreshEnv.new(['x'], goal)
|
234
|
+
instance = RunStarExpression.new('q', fresh_env)
|
235
|
+
|
236
|
+
result = instance.run
|
237
|
+
|
238
|
+
# Does propagate work correctly?
|
239
|
+
expect(ref_q.fresh?(instance.env)).to be_truthy # x isn't defined here
|
240
|
+
expect(ref_q.fresh?(fresh_env)).to be_falsey
|
241
|
+
expect(ref_x.fresh?(fresh_env)).to be_falsey
|
242
|
+
expect(result.car).to eq(pod)
|
243
|
+
end
|
244
|
+
end # context
|
245
|
+
end # describe
|
246
|
+
end # module
|
247
|
+
end # module
|