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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10a0607b5621effb10eab26d64ff7f52228f93e9c7907b91488613c1d72469aa
4
- data.tar.gz: 9b43c9b0d729f2c7944be72f6599decae48d977ea0be5257a365111508473ef9
3
+ metadata.gz: ec7b984a9f0c857f74c8a8989c5da2072398775573b7ca6679d99f96ef13eac1
4
+ data.tar.gz: cdebdebae82c424b9ae701f959765f0905322798a371e2aec42ed9a229e35a4f
5
5
  SHA512:
6
- metadata.gz: 32c14d82b93ddf21d2b369745b1e556faf1736b53fd7f1782809370777e059c498e1d8347806dc2135aab3bedf429c8d2b93b5f9be4b9b361f86926edb1be20f
7
- data.tar.gz: 9b82b3afd53af4da54042f8a8852367250bc8225c1229b31486b4e8223ca533d55f3dcc6250c4de4c03d0d84b77a5e5cf737a6c151f734d7a08334ac442fa330
6
+ metadata.gz: 2ce3553527adeebef7adc69ec5a861fe65f9f451e54a81e23f00769923ced6b6a6011846ae3e9a673c8b9094a7dcce6ea6f8d263d55c8f543ef0de309e34c11c
7
+ data.tar.gz: 90b45061cde1119ad648359063682f411f9e5705a294340976bd027561b1d94da7afbfc9d0d27dce67942e1407d4d4ea40df85cf3fe67c9fca998d22052b6187
@@ -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
- voc.clear if outcome1&.successful? && outcome2&.successful?
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.new(:"#s", anEnv)
34
+ result = Outcome.success(anEnv)
35
35
  else
36
- result = Failure
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.new(:"#s", anEnv) if arg1.equal?(arg2)
74
+ return Outcome.success(anEnv) if arg1.equal?(arg2)
74
75
 
75
- result = Outcome.new(:"#u", anEnv) # default case
76
+ result = Outcome.failure(anEnv) # default case
76
77
 
77
78
  if arg1.kind_of?(AtomicTerm)
78
- result = BasicSuccess if arg1.eql?(arg2)
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.new(:"#s", anEnv)
88
+ result = Outcome.success(anEnv)
88
89
  arg1.associate(arg2, result)
89
90
  else
90
- result = Outcome.new(:"#s", anEnv) if arg1.value(anEnv).eql?(arg2)
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.new(:"#s", anEnv)
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.new(:"#s", anEnv)
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.new(:"#u", anEnv)
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.new(:"#s", anEnv)
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
@@ -33,6 +33,12 @@ module MiniKraken
33
33
  goal.attain(self)
34
34
  end
35
35
 
36
+ protected
37
+
38
+ def introspect
39
+ +", @vars=[#{vars.keys.join(', ')}]"
40
+ end
41
+
36
42
  private
37
43
 
38
44
  def valid_goal(aGoal)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniKraken
4
- VERSION = '0.1.09'
4
+ VERSION = '0.1.10'
5
5
  end
@@ -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)) (,x)) `(((,x)) pod)))) ;; => ('pod)
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.09
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-06 00:00:00.000000000 Z
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