mini_kraken 0.1.09 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|