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 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