mini_kraken 0.1.09 → 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/CHANGELOG.md +11 -0
- data/lib/mini_kraken/core/conj2.rb +4 -1
- data/lib/mini_kraken/core/equals.rb +15 -11
- data/lib/mini_kraken/core/outcome.rb +14 -0
- data/lib/mini_kraken/core/vocabulary.rb +16 -0
- data/lib/mini_kraken/glue/fresh_env.rb +6 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/spec/core/equals_spec.rb +3 -3
- data/spec/core/outcome_spec.rb +48 -0
- data/spec/core/vocabulary_spec.rb +6 -0
- data/spec/glue/run_star_expression_spec.rb +119 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec7b984a9f0c857f74c8a8989c5da2072398775573b7ca6679d99f96ef13eac1
|
4
|
+
data.tar.gz: cdebdebae82c424b9ae701f959765f0905322798a371e2aec42ed9a229e35a4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ce3553527adeebef7adc69ec5a861fe65f9f451e54a81e23f00769923ced6b6a6011846ae3e9a673c8b9094a7dcce6ea6f8d263d55c8f543ef0de309e34c11c
|
7
|
+
data.tar.gz: 90b45061cde1119ad648359063682f411f9e5705a294340976bd027561b1d94da7afbfc9d0d27dce67942e1407d4d4ea40df85cf3fe67c9fca998d22052b6187
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## [0.1.10] - 2020-06-10
|
2
|
+
- Supports frames from "The Reasoned Scheme" book up to frame [1:81]
|
3
|
+
|
4
|
+
### New
|
5
|
+
- Factory methods `Outcome#failure`, `Outcome#success`
|
6
|
+
- Method `Vocabulary#inspect`
|
7
|
+
- File `outcome_spec.rb`
|
8
|
+
|
9
|
+
### FIXED
|
10
|
+
- `Conj2#conjunction` vocabulary wasn't cleared when outcome2 was nil.
|
11
|
+
|
1
12
|
## [0.1.09] - 2020-06-06
|
2
13
|
- Supports frames from "The Reasoned Scheme" book up to frame [1:76]
|
3
14
|
|
@@ -31,6 +31,7 @@ unless MiniKraken::Core.constants(false).include? :Conj2
|
|
31
31
|
# @param g2 [Goal] Second goal argument
|
32
32
|
# @param voc [Vocabulary] A vocabulary object
|
33
33
|
def conjunction(g1, g2, voc)
|
34
|
+
# require 'debug'
|
34
35
|
if g1.relation.kind_of?(Fail) || g2.relation.kind_of?(Fail)
|
35
36
|
Fiber.yield Outcome.new(:"#u", voc)
|
36
37
|
else
|
@@ -62,7 +63,9 @@ unless MiniKraken::Core.constants(false).include? :Conj2
|
|
62
63
|
else
|
63
64
|
Fiber.yield outcome1
|
64
65
|
end
|
65
|
-
|
66
|
+
if outcome1.successful? && (outcome2&.successful? || outcome2.nil?)
|
67
|
+
voc.clear
|
68
|
+
end
|
66
69
|
end
|
67
70
|
end
|
68
71
|
|
@@ -31,9 +31,9 @@ unless MiniKraken::Core.constants(false).include? :Equals
|
|
31
31
|
arg2_nil = arg2.nil?
|
32
32
|
if arg1_nil || arg2_nil
|
33
33
|
if arg1_nil && arg2_nil
|
34
|
-
result = Outcome.
|
34
|
+
result = Outcome.success(anEnv)
|
35
35
|
else
|
36
|
-
result =
|
36
|
+
result = Outcome.failure(anEnv)
|
37
37
|
end
|
38
38
|
return result
|
39
39
|
end
|
@@ -46,6 +46,7 @@ unless MiniKraken::Core.constants(false).include? :Equals
|
|
46
46
|
|
47
47
|
private
|
48
48
|
|
49
|
+
|
49
50
|
# table: Unification
|
50
51
|
# | arg1 | arg2 | Criterion || Unification |
|
51
52
|
# | isa? Atomic | isa? Atomic | arg1.eq? arg2 is true || { "s", [] } |
|
@@ -70,12 +71,12 @@ unless MiniKraken::Core.constants(false).include? :Equals
|
|
70
71
|
# | | unification(arg1, arg2.value) => "u" || { "u", [] }
|
71
72
|
def do_unification(arg1, arg2, anEnv)
|
72
73
|
# require 'debug'
|
73
|
-
return Outcome.
|
74
|
+
return Outcome.success(anEnv) if arg1.equal?(arg2)
|
74
75
|
|
75
|
-
result = Outcome.
|
76
|
+
result = Outcome.failure(anEnv) # default case
|
76
77
|
|
77
78
|
if arg1.kind_of?(AtomicTerm)
|
78
|
-
result =
|
79
|
+
result = Outcome.success(anEnv) if arg1.eql?(arg2)
|
79
80
|
elsif arg1.kind_of?(CompositeTerm)
|
80
81
|
if arg2.kind_of?(CompositeTerm) # AtomicTerm is default case => fail
|
81
82
|
result = unify_composite_terms(arg1, arg2, anEnv)
|
@@ -84,14 +85,14 @@ unless MiniKraken::Core.constants(false).include? :Equals
|
|
84
85
|
arg1_freshness = arg1.freshness(anEnv)
|
85
86
|
if arg2.kind_of?(AtomicTerm)
|
86
87
|
if arg1_freshness.degree == :fresh
|
87
|
-
result = Outcome.
|
88
|
+
result = Outcome.success(anEnv)
|
88
89
|
arg1.associate(arg2, result)
|
89
90
|
else
|
90
|
-
result = Outcome.
|
91
|
+
result = Outcome.success(anEnv) if arg1.value(anEnv).eql?(arg2)
|
91
92
|
end
|
92
93
|
elsif arg2.kind_of?(CompositeTerm)
|
93
94
|
if arg1_freshness.degree == :fresh
|
94
|
-
result = Outcome.
|
95
|
+
result = Outcome.success(anEnv)
|
95
96
|
arg1.associate(arg2, result)
|
96
97
|
else
|
97
98
|
# Ground case...
|
@@ -103,11 +104,14 @@ unless MiniKraken::Core.constants(false).include? :Equals
|
|
103
104
|
when [false, false] # TODO: confirm this...
|
104
105
|
result = unification(arg1.value(anEnv), arg2.value(anEnv), anEnv)
|
105
106
|
when [true, true]
|
106
|
-
result = Outcome.
|
107
|
+
result = Outcome.success(anEnv)
|
107
108
|
if arg1.var_name != arg2.var_name
|
108
109
|
arg1.associate(arg2, result)
|
109
110
|
arg2.associate(arg1, result)
|
110
111
|
end
|
112
|
+
when [true, false]
|
113
|
+
result = Outcome.success(anEnv)
|
114
|
+
arg1.associate(arg2, result)
|
111
115
|
else
|
112
116
|
raise StandardError, "Unsupported freshness combination #{freshness}"
|
113
117
|
end
|
@@ -123,7 +127,7 @@ unless MiniKraken::Core.constants(false).include? :Equals
|
|
123
127
|
# @return [Freshness]
|
124
128
|
def unify_composite_terms(arg1, arg2, anEnv)
|
125
129
|
# require 'debug'
|
126
|
-
result = Outcome.
|
130
|
+
result = Outcome.failure(anEnv)
|
127
131
|
children1 = arg1.children
|
128
132
|
children2 = arg2.children
|
129
133
|
|
@@ -136,7 +140,7 @@ unless MiniKraken::Core.constants(false).include? :Equals
|
|
136
140
|
end
|
137
141
|
total_success = subresults.all?(&:successful?)
|
138
142
|
if total_success
|
139
|
-
memo = Outcome.
|
143
|
+
memo = Outcome.success(anEnv)
|
140
144
|
associations = subresults.reduce(memo) do |sub_total, outcome|
|
141
145
|
sub_total.merge(outcome)
|
142
146
|
sub_total
|
@@ -16,6 +16,14 @@ unless MiniKraken::Core.constants(false).include? :Outcome
|
|
16
16
|
@resultant = aResult
|
17
17
|
end
|
18
18
|
|
19
|
+
def self.failure(aParent = nil)
|
20
|
+
new(:"#u", aParent)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.success(aParent = nil)
|
24
|
+
new(:"#s", aParent)
|
25
|
+
end
|
26
|
+
|
19
27
|
def successful?
|
20
28
|
resultant == :"#s"
|
21
29
|
end
|
@@ -30,6 +38,12 @@ unless MiniKraken::Core.constants(false).include? :Outcome
|
|
30
38
|
|
31
39
|
are_equal
|
32
40
|
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def introspect
|
45
|
+
", @resultant=#{resultant}"
|
46
|
+
end
|
33
47
|
end # class
|
34
48
|
|
35
49
|
Failure = Outcome.new(:"#u")
|
@@ -394,6 +394,18 @@ module MiniKraken
|
|
394
394
|
name2var(aVarName) ? true : false
|
395
395
|
end
|
396
396
|
|
397
|
+
def inspect
|
398
|
+
result = +"#<#{self.class.name}:#{object_id.to_s(16)} @parent="
|
399
|
+
if parent
|
400
|
+
result << "#<#{parent.class.name}:#{parent.object_id.to_s(16)}>"
|
401
|
+
else
|
402
|
+
result << nil
|
403
|
+
end
|
404
|
+
result << introspect
|
405
|
+
result << '>'
|
406
|
+
result
|
407
|
+
end
|
408
|
+
|
397
409
|
protected
|
398
410
|
|
399
411
|
def validated_parent(aParent)
|
@@ -420,6 +432,10 @@ module MiniKraken
|
|
420
432
|
assc
|
421
433
|
end
|
422
434
|
end
|
435
|
+
|
436
|
+
def introspect
|
437
|
+
''
|
438
|
+
end
|
423
439
|
end # class
|
424
440
|
end # module
|
425
441
|
end # module
|
data/lib/mini_kraken/version.rb
CHANGED
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
|
@@ -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
|
@@ -65,6 +65,7 @@ module MiniKraken
|
|
65
65
|
let(:ref_s) { Core::VariableRef.new('s') }
|
66
66
|
let(:ref_t) { Core::VariableRef.new('t') }
|
67
67
|
let(:ref_u) { Core::VariableRef.new('u') }
|
68
|
+
let(:ref_z) { Core::VariableRef.new('z') }
|
68
69
|
|
69
70
|
it 'should return a null list with the fail goal' do
|
70
71
|
# Reasoned S2, frame 1:7
|
@@ -662,6 +663,124 @@ module MiniKraken
|
|
662
663
|
expect(result.cdr.car.car).to eq(red)
|
663
664
|
expect(result.cdr.car.cdr.car).to eq(bean)
|
664
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
|
665
784
|
end # context
|
666
785
|
end # describe
|
667
786
|
end # module
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_kraken
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -112,6 +112,7 @@ files:
|
|
112
112
|
- spec/core/fail_spec.rb
|
113
113
|
- spec/core/goal_spec.rb
|
114
114
|
- spec/core/k_symbol_spec.rb
|
115
|
+
- spec/core/outcome_spec.rb
|
115
116
|
- spec/core/succeed_spec.rb
|
116
117
|
- spec/core/variable_ref_spec.rb
|
117
118
|
- spec/core/variable_spec.rb
|
@@ -157,6 +158,7 @@ test_files:
|
|
157
158
|
- spec/core/fail_spec.rb
|
158
159
|
- spec/core/goal_spec.rb
|
159
160
|
- spec/core/k_symbol_spec.rb
|
161
|
+
- spec/core/outcome_spec.rb
|
160
162
|
- spec/core/succeed_spec.rb
|
161
163
|
- spec/core/variable_ref_spec.rb
|
162
164
|
- spec/core/variable_spec.rb
|