mini_kraken 0.2.02 → 0.2.03

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