mini_kraken 0.2.02 → 0.2.03

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: 24222422e142dde60f6f5a3c92ca1b4967eb358f26d29a0d834f719d25fcab11
4
- data.tar.gz: 855880806c2210763e6c77d442f8d0463c39b9bde81072ff91f65ca21a275998
3
+ metadata.gz: 6ae3703cbb0a7a854af490478227c915d7d9af72715be80cbd4e3c95cb7b2c3f
4
+ data.tar.gz: 27e04d428e1015f176fbafba7c047a0b12c28e9150161a7a5702190c8dd2e2e9
5
5
  SHA512:
6
- metadata.gz: e7840d5f469d0924b5018a87ca9e349f7c17f81fb23c1b8001890f9b5ca752125fae2de08eb10af1e8fc430347dba3c1a635e25fe7c188196f93415ccaecbe95
7
- data.tar.gz: 3a16f04afa89e31dbe572af6c26eeafb169143dc5d55419f4db1ee0c90b0268c60e0a1bee643a3bcdce769e3fd524dd6be37b8ad60211d814321f5b90e7f3350
6
+ metadata.gz: bd9cd60953f88610ce3a5009e0cad4099e1896643ad01f1c6616a4c20fb4495a71f5c5ed11efe98873362055bda2ec9d0ba4a1ce972844588cacab528ac5333d
7
+ data.tar.gz: 1c9d27a9fb7fa014f9789a159aff5309bd9c03ce810e994951373ee550698518683359815c4db43b9d95b00ba889670b824af18c1019af5442f2ca3b42c795ba
@@ -1,3 +1,21 @@
1
+ ## [0.2.03] - 2020-09-02
2
+ - The DSL (Domain Specific Language) supports the `caro` relation & passes frames up to 2-8 from Chapter 2.
3
+
4
+ ### NEW
5
+ - Class `ConsCellVisitor`. Its method `df_visitor` builds a Fiber that walks over a ConsCell (list/graph).
6
+ - Method `Outcome#failure?`
7
+ - Method `Outcome#prune!` for removing associations of transient variables.
8
+ - Method `VariableRef#to_s` for providing a text representation of a variable reference
9
+ - Method `Vocabulary#prune` for removing associations of transient variables.
10
+ - Class `FreshEnvFactory` as its name implies, is used to build `FreshEnv` instances.
11
+
12
+ ### CHANGED
13
+ - Method `Outcome#successful?` renamed to `Outcome#success?`
14
+
15
+ ### FIXED
16
+ - Method `Equals#solver_for` now prunes associations of transient variables.
17
+ - Method `Equals#unify_composite_terms` now copes with Conscell vs. VariableRef unification.
18
+
1
19
  ## [0.2.02] - 2020-08-08
2
20
  - The DSL (Domain Specific Language) now supports `conde` and passes all examples from Chapter 1.
3
21
 
data/README.md CHANGED
@@ -23,14 +23,14 @@ ISBN: 9780262535519, (2018), MIT Press.
23
23
  - [X] conde
24
24
  - [X] conj2
25
25
  - [X] disj2
26
- - [X] defrel
26
+ - [X] defrel
27
+ - [X] caro
27
28
 
28
29
  ### TODO
29
30
 
30
31
  - [ ] Occurs check
31
32
 
32
- List-centric relations from Chapter 2
33
- - [ ] caro
33
+ List-centric relations from Chapter 2
34
34
  - [ ] cdro
35
35
  - [ ] conso
36
36
  - [ ] nullo
@@ -12,4 +12,3 @@ module MiniKraken
12
12
  end
13
13
 
14
14
  # End of file
15
-
@@ -63,7 +63,7 @@ unless MiniKraken::Core.constants(false).include? :Conde
63
63
  break unless outcome
64
64
 
65
65
  outcome.parent = voc unless outcome.parent
66
- if outcome.successful?
66
+ if outcome.success?
67
67
  success = true
68
68
  Fiber.yield outcome
69
69
  outcome.clear
@@ -43,14 +43,14 @@ unless MiniKraken::Core.constants(false).include? :Conj2
43
43
  break unless outcome1
44
44
 
45
45
  outcome1.parent = voc unless outcome1.parent
46
- if outcome1.successful?
46
+ if outcome1.success?
47
47
  f2 = g2.attain(outcome1)
48
48
  loop do
49
49
  outcome2 = f2.resume
50
50
  break unless outcome2
51
51
 
52
52
  outcome2.parent = voc unless outcome2.parent
53
- if outcome2.successful?
53
+ if outcome2.success?
54
54
  res = Outcome.new(:"#s", voc)
55
55
  res.merge(outcome1)
56
56
  res.merge(outcome2)
@@ -63,7 +63,7 @@ unless MiniKraken::Core.constants(false).include? :Conj2
63
63
  else
64
64
  Fiber.yield outcome1
65
65
  end
66
- if outcome1.successful? && (outcome2&.successful? || outcome2.nil?)
66
+ if outcome1.success? && (outcome2&.success? || outcome2.nil?)
67
67
  voc.clear
68
68
  end
69
69
  end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require_relative 'cons_cell'
5
+
6
+ module MiniKraken
7
+ module Core
8
+ # Factory class.
9
+ # Purpose: to create an enumerator specialized in the visit of cons cells.
10
+ class ConsCellVisitor
11
+ # Build a depth-first in-order expression tree visitor.
12
+ # The visitor is implemented as an Enumerator.
13
+ # The enumerator returns couples of the form: [:car or :cdr or :nil, visitee]
14
+ # [anExpr] the term to visit.
15
+ # @param aCell [ConsCell]
16
+ # @return [Fiber]
17
+ def self.df_visitor(aCell)
18
+ first = aCell # The visit will start from the provided cons cell
19
+ visitor = Fiber.new do |skipping|
20
+ # Initialization part: will run once
21
+ visitees = Set.new # Keep track of the conscell already visited
22
+ visit_stack = first.nil? ? [] : [[:car, first]] # The LIFO queue of cells to visit
23
+
24
+ until visit_stack.empty? # Traversal part (as a loop)
25
+ to_swap = false
26
+ side, cell = visit_stack.pop
27
+ next if visitees.include?(cell)
28
+
29
+ visitees << cell
30
+
31
+ skip_children = Fiber.yield [side, cell]
32
+ # require 'debug' if skip_children
33
+ next if skip_children || skipping
34
+
35
+ skipping = false
36
+ case cell.car
37
+ when ConsCell
38
+ visit_stack.push([:car, cell.car])
39
+ to_swap = true
40
+ else
41
+ Fiber.yield [:car, cell.car]
42
+ end
43
+
44
+ case cell.cdr
45
+ when ConsCell
46
+ if to_swap
47
+ visit_stack.insert(-2, [:cdr, cell.cdr])
48
+ else
49
+ visit_stack.push([:cdr, cell.cdr])
50
+ end
51
+ else
52
+ Fiber.yield [:cdr, cell.cdr]
53
+ end
54
+ end
55
+
56
+ # Send stop mark
57
+ Fiber.yield [:stop, nil]
58
+ end
59
+
60
+ =begin
61
+ visitor = Enumerator.new do |requester| # requester argument is a Yielder
62
+ # Initialization part: will run once
63
+ visitees = Set.new # Keep track of the conscell already visited
64
+ visit_stack = first.nil? ? [] : [[ :car, first ]] # The LIFO queue of cells to visit
65
+
66
+ until visit_stack.empty? # Traversal part (as a loop)
67
+ to_swap = false
68
+ side, cell = visit_stack.pop()
69
+ next if visitees.include?(cell)
70
+
71
+ requester << [side, cell]
72
+ case cell.car
73
+ when ConsCell
74
+ visit_stack.push([:car, cell.car])
75
+ to_swap = true
76
+ else
77
+ requester << [:car, cell.car]
78
+ end
79
+
80
+ case cell.cdr
81
+ when ConsCell
82
+ if to_swap
83
+ visit_stack.insert(-2, [:cdr, cell.cdr])
84
+ else
85
+ visit_stack.push([:cdr, cell.cdr])
86
+ end
87
+ else
88
+ requester << [:cdr, cell.cdr]
89
+ end
90
+
91
+ visitees << cell
92
+ end
93
+
94
+ # Send stop mark
95
+ requester << [:stop, nil]
96
+ end
97
+ =end
98
+ return visitor
99
+ end
100
+ end # class
101
+ end # module
102
+ end # module
@@ -15,6 +15,7 @@ module MiniKraken
15
15
 
16
16
  # @param aName [String] name of def relation
17
17
  # @param aGoalTemplate [GoalTemplate]
18
+ # @param theFormals [Array<FormalArg>]
18
19
  def initialize(aName, aGoalTemplate, theFormals, alternateName = nil)
19
20
  super(aName, alternateName)
20
21
  @formals = validated_formals(theFormals)
@@ -43,6 +44,8 @@ module MiniKraken
43
44
  end
44
45
 
45
46
  def validated_goal_template(aGoalTemplate)
47
+ raise StandardError unless aGoalTemplate
48
+
46
49
  aGoalTemplate
47
50
  end
48
51
  end # class
@@ -44,7 +44,7 @@ unless MiniKraken::Core.constants(false).include? :Disj2
44
44
  break unless outcome1
45
45
 
46
46
  outcome1.parent = voc unless outcome1.parent
47
- if outcome1.successful?
47
+ if outcome1.success?
48
48
  Fiber.yield outcome1
49
49
  outcome1.clear
50
50
  end
@@ -55,7 +55,7 @@ unless MiniKraken::Core.constants(false).include? :Disj2
55
55
  break unless outcome2
56
56
 
57
57
  outcome2.parent = voc unless outcome2.parent
58
- if outcome2.successful?
58
+ if outcome2.success?
59
59
  Fiber.yield outcome2
60
60
  outcome2.clear
61
61
  end
@@ -57,7 +57,7 @@ module MiniKraken
57
57
  # Roll up associations from descendent outcome object
58
58
  # @param descendent [Outcome]
59
59
  def do_propagate(descendent)
60
- return unless descendent.successful?
60
+ return unless descendent.success?
61
61
 
62
62
  vars.each_key do |var_name|
63
63
  # assocs = descendent[var_name]
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'singleton'
4
4
  require_relative 'binary_relation'
5
- # require_relative 'any_value'
5
+ require_relative 'cons_cell_visitor'
6
6
  require_relative 'duck_fiber'
7
7
  require_relative 'variable'
8
8
  require_relative 'variable_ref'
@@ -23,7 +23,10 @@ unless MiniKraken::Core.constants(false).include? :Equals
23
23
  # @return [Fiber<Outcome>] A Fiber(-like) instance that yields Outcomes
24
24
  def solver_for(actuals, anEnv)
25
25
  arg1, arg2 = *actuals
26
- DuckFiber.new(:custom) { unification(arg1, arg2, anEnv) }
26
+ DuckFiber.new(:custom) do
27
+ outcome = unification(arg1, arg2, anEnv)
28
+ outcome.prune!
29
+ end
27
30
  end
28
31
 
29
32
  def unification(arg1, arg2, anEnv)
@@ -93,7 +96,10 @@ unless MiniKraken::Core.constants(false).include? :Equals
93
96
  arg1.associate(arg2, result)
94
97
  else
95
98
  # Ground case...
96
- result = unify_composite_terms(arg1_freshness.associated, arg2, anEnv)
99
+ arg1_associated = arg1_freshness.associated
100
+ unless arg1_associated.kind_of?(AtomicTerm)
101
+ result = unify_composite_terms(arg1_associated, arg2, anEnv)
102
+ end
97
103
  end
98
104
  elsif arg2.kind_of?(VariableRef)
99
105
  freshness = [arg1.fresh?(anEnv), arg2.fresh?(anEnv)]
@@ -121,33 +127,64 @@ unless MiniKraken::Core.constants(false).include? :Equals
121
127
  result
122
128
  end
123
129
 
124
- # @return [Freshness]
130
+ # @param arg1 [ConsCell]
131
+ # @param arg2 [ConsCell]
132
+ # @return [Outcome]
125
133
  def unify_composite_terms(arg1, arg2, anEnv)
126
134
  # require 'debug'
127
- result = Outcome.failure(anEnv)
128
- children1 = arg1.children
129
- children2 = arg2.children
130
-
131
- if children1.size == children2.size
132
- i = 0
133
- subresults = children1.map do |child1|
134
- child2 = children2[i]
135
- i += 1
136
- unification(child1, child2, anEnv)
137
- end
138
- total_success = subresults.all?(&:successful?)
139
- if total_success
140
- memo = Outcome.success(anEnv)
141
- subresults.reduce(memo) do |sub_total, outcome|
142
- sub_total.merge(outcome)
143
- sub_total
135
+ result = Outcome.success(anEnv)
136
+ # We'll do parallel iteration
137
+ visitor1 = ConsCellVisitor.df_visitor(arg1)
138
+ visitor2 = ConsCellVisitor.df_visitor(arg2)
139
+ skip_children1 = false
140
+ skip_children2 = false
141
+
142
+ loop do
143
+ side1, cell1 = visitor1.resume(skip_children1)
144
+ side2, cell2 = visitor2.resume(skip_children2)
145
+ if side1 != side2
146
+ result = Outcome.failure(anEnv)
147
+ elsif side1 == :stop
148
+ break
149
+ else
150
+ case [cell1.class, cell2.class] # nil, AtomicTerm, ConsCell, VariableRef
151
+ when [ConsCell, ConsCell]
152
+ skip_children1 = false
153
+ skip_children2 = false
154
+ when [ConsCell, VariableRef]
155
+ skip_children1 = true
156
+ skip_children2 = false
157
+ sub_result = unification(cell1, cell2, anEnv)
158
+ result = merge_results(result, sub_result)
159
+ when [VariableRef, ConsCell]
160
+ skip_children1 = false
161
+ skip_children2 = true
162
+ sub_result = do_unification(cell1, cell2, anEnv)
163
+ result = merge_results(result, sub_result)
164
+ else
165
+ skip_children1 = false
166
+ skip_children2 = false
167
+ sub_result = unification(cell1, cell2, anEnv)
168
+ result = merge_results(result, sub_result)
144
169
  end
145
- result = memo
146
170
  end
171
+
172
+ break if result.failure?
147
173
  end
148
174
 
149
175
  result
150
176
  end
177
+
178
+ def merge_results(result1, result2)
179
+ raise StandardError if result2.kind_of?(Hash)
180
+
181
+ if result2.success?
182
+ result1.merge(result2)
183
+ result1
184
+ else
185
+ result2
186
+ end
187
+ end
151
188
  end # class
152
189
 
153
190
  Equals.instance.freeze
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'base_arg'
4
+ require_relative 'cons_cell_visitor'
4
5
 
5
6
  module MiniKraken
6
7
  module Core
7
8
  # A meta-goal that is parametrized with generic formal arguments.
8
9
  # The individual goals are instantiated when the formal arguments
9
- # are bound to goal arguments
10
+ # are bound to goal arguments.
10
11
  class GoalTemplate < BaseArg
11
12
  # @return [Array<BaseArg>] Arguments of goal template.
12
13
  attr_reader :args
@@ -14,13 +15,16 @@ module MiniKraken
14
15
  # @return [Relation] Main relation for the goal template
15
16
  attr_reader :relation
16
17
 
18
+ # @param aRelation [Core::Rzlation] the relation
19
+ # @param theArgs [Array<Core::BaseArg>] Arguments of goal template.
17
20
  def initialize(aRelation, theArgs)
18
21
  super()
19
22
  @relation = validated_relation(aRelation)
20
23
  @args = validated_args(theArgs)
21
- freeze
24
+ args.freeze
22
25
  end
23
26
 
27
+ # Factory method: Create a goal object.
24
28
  # @param formals [Array<FormalArg>] Array of formal arguments
25
29
  # @param actuals [Array<GoalArg>] Array of actual arguments
26
30
  # @return [Goal] instantiate a goal object given the actuals and environment
@@ -50,6 +54,9 @@ module MiniKraken
50
54
  goal_args << formals2actuals[arg.name]
51
55
  elsif arg.kind_of?(GoalTemplate)
52
56
  goal_args << arg.send(:do_instantiate, formals2actuals)
57
+ elsif arg.kind_of?(ConsCell)
58
+ # if list contains a formal_ref it must be replaced by the actual
59
+ goal_args << transform(arg, formals2actuals)
53
60
  else
54
61
  goal_args << arg
55
62
  end
@@ -57,6 +64,39 @@ module MiniKraken
57
64
 
58
65
  Goal.new(relation, goal_args)
59
66
  end
67
+
68
+ private
69
+
70
+ def transform(aConsCell, formals2actuals)
71
+ return aConsCell if aConsCell.null?
72
+
73
+ member = { car: :@car, cdr: :@cdr }
74
+ visitor = ConsCellVisitor.df_visitor(aConsCell)
75
+ side, cell = visitor.resume
76
+ result = ConsCell.new(nil, nil)
77
+ node = result
78
+
79
+ loop do
80
+ side, cell = visitor.resume
81
+ break if side == :stop
82
+
83
+ converted = nil
84
+ case cell
85
+ when FormalRef
86
+ converted = formals2actuals[cell.name]
87
+ when ConsCell
88
+ converted = ConsCell.new(nil, nil)
89
+ when GoalTemplate
90
+ converted = cell.send(:do_instantiate, formals2actuals)
91
+ else
92
+ converted = cell
93
+ end
94
+ node.instance_variable_set(member[side], converted)
95
+ node = converted if converted.kind_of?(ConsCell)
96
+ end
97
+
98
+ result
99
+ end
60
100
  end # class
61
101
  end # module
62
102
  end # module
@@ -11,7 +11,7 @@ module MiniKraken
11
11
  def initialize(aValue)
12
12
  super(validated_value(aValue))
13
13
  end
14
-
14
+
15
15
  def to_s
16
16
  value.to_s
17
17
  end