mini_kraken 0.2.03 → 0.2.04

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/lib/mini_kraken/atomic/all_atomic.rb +4 -0
  4. data/lib/mini_kraken/{core → atomic}/atomic_term.rb +23 -9
  5. data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
  6. data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -1
  7. data/lib/mini_kraken/{core → atomic}/k_symbol.rb +5 -3
  8. data/lib/mini_kraken/{core → composite}/composite_term.rb +6 -4
  9. data/lib/mini_kraken/composite/cons_cell.rb +132 -0
  10. data/lib/mini_kraken/{core → composite}/cons_cell_visitor.rb +1 -1
  11. data/lib/mini_kraken/core/association_walker.rb +14 -14
  12. data/lib/mini_kraken/core/binary_relation.rb +10 -10
  13. data/lib/mini_kraken/core/equals.rb +159 -161
  14. data/lib/mini_kraken/core/goal_relation.rb +2 -2
  15. data/lib/mini_kraken/core/goal_template.rb +7 -7
  16. data/lib/mini_kraken/core/{variable.rb → log_var.rb} +10 -3
  17. data/lib/mini_kraken/core/{variable_ref.rb → log_var_ref.rb} +3 -3
  18. data/lib/mini_kraken/core/tap.rb +46 -0
  19. data/lib/mini_kraken/core/vocabulary.rb +8 -8
  20. data/lib/mini_kraken/glue/dsl.rb +21 -17
  21. data/lib/mini_kraken/glue/fresh_env.rb +7 -2
  22. data/lib/mini_kraken/glue/fresh_env_factory.rb +1 -1
  23. data/lib/mini_kraken/glue/run_star_expression.rb +2 -2
  24. data/lib/mini_kraken/version.rb +1 -1
  25. data/spec/.rubocop.yml +1 -1
  26. data/spec/atomic/atomic_term_spec.rb +94 -0
  27. data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
  28. data/spec/{core → atomic}/k_symbol_spec.rb +3 -11
  29. data/spec/{core → composite}/cons_cell_spec.rb +10 -8
  30. data/spec/{core → composite}/cons_cell_visitor_spec.rb +11 -10
  31. data/spec/core/association_spec.rb +6 -4
  32. data/spec/core/association_walker_spec.rb +8 -6
  33. data/spec/core/conde_spec.rb +19 -17
  34. data/spec/core/conj2_spec.rb +10 -8
  35. data/spec/core/def_relation_spec.rb +9 -7
  36. data/spec/core/disj2_spec.rb +11 -10
  37. data/spec/core/environment_spec.rb +12 -10
  38. data/spec/core/equals_spec.rb +12 -10
  39. data/spec/core/goal_spec.rb +6 -5
  40. data/spec/core/goal_template_spec.rb +5 -5
  41. data/spec/core/{variable_ref_spec.rb → log_var_ref_spec.rb} +4 -4
  42. data/spec/core/{variable_spec.rb → log_var_spec.rb} +4 -4
  43. data/spec/core/vocabulary_spec.rb +12 -11
  44. data/spec/glue/dsl_chap1_spec.rb +0 -45
  45. data/spec/glue/dsl_chap2_spec.rb +115 -7
  46. data/spec/glue/fresh_env_factory_spec.rb +11 -9
  47. data/spec/glue/fresh_env_spec.rb +3 -3
  48. data/spec/glue/run_star_expression_spec.rb +13 -11
  49. data/spec/support/factory_atomic.rb +22 -0
  50. data/spec/support/factory_methods.rb +11 -26
  51. metadata +28 -23
  52. data/lib/mini_kraken/core/cons_cell.rb +0 -82
  53. data/lib/mini_kraken/core/k_boolean.rb +0 -35
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require_relative 'duck_fiber'
5
+ require_relative 'goal'
6
+ require_relative 'goal_relation'
7
+ require_relative 'outcome'
8
+
9
+ module MiniKraken
10
+ module Core
11
+ class Tap < GoalRelation
12
+ include Singleton
13
+
14
+ def initialize
15
+ super('tap', nil)
16
+ end
17
+
18
+ def arity
19
+ 1
20
+ end
21
+
22
+ # @param actuals [Array<Term>] A two-elements array
23
+ # @param anEnv [Vocabulary] A vocabulary object
24
+ # @return [Fiber<Outcome>] A Fiber that yields Outcomes objects
25
+ def solver_for(actuals, anEnv)
26
+ args = *validated_args(actuals)
27
+ DuckFiber.new(:custom) do
28
+ outcome = tap(args.first, anEnv)
29
+ # outcome.prune!
30
+ end
31
+ end
32
+
33
+ def tap(aGoal, anEnv)
34
+ require 'debug'
35
+ f1 = aGoal.attain(anEnv)
36
+ outcome1 = f1.resume
37
+ # key = outcome1.associations.keys.first
38
+ # outcome1.associations['x'] = outcome1.associations[key]
39
+ # outcome1.associations.delete(key)
40
+ outcome1
41
+ end
42
+ end # class
43
+
44
+ Tap.instance.freeze
45
+ end # module
46
+ end # module
@@ -138,12 +138,12 @@ module MiniKraken
138
138
  # Check that the provided variable must be fused with the argument.
139
139
  # @return [Array<Variable>]
140
140
  def detect_fuse(aVariable, aTerm)
141
- return [] unless aTerm.kind_of?(VariableRef)
141
+ return [] unless aTerm.kind_of?(LogVarRef)
142
142
 
143
143
  assocs = self[aTerm.var_name]
144
144
  # Simplified implementation: cope with binary cycles only...
145
145
  # TODO: Extend to n-ary (n > 2) cycles
146
- assoc_refs = assocs.select { |a| a.value.kind_of?(VariableRef) }
146
+ assoc_refs = assocs.select { |a| a.value.kind_of?(LogVarRef) }
147
147
  return [] if assoc_refs.empty? # No relevant association...
148
148
 
149
149
  visitees = Set.new
@@ -159,7 +159,7 @@ module MiniKraken
159
159
  to_fuse << assc.i_name unless assc.i_name == aVariable.i_name
160
160
  end
161
161
  other_assocs = self[ref.var_name]
162
- other_assoc_refs = other_assocs.select { |a| a.value.kind_of?(VariableRef) }
162
+ other_assoc_refs = other_assocs.select { |a| a.value.kind_of?(LogVarRef) }
163
163
  other_assoc_refs.each do |a|
164
164
  to_visit << a unless visitess.include?(a)
165
165
  end
@@ -192,7 +192,7 @@ module MiniKraken
192
192
  if voc.associations.include?(old_i_name)
193
193
  assocs = voc.associations[old_i_name]
194
194
  keep_assocs = assocs.reject do |assc|
195
- assc.value.kind_of?(VariableRef) && old_names.include?(assc.value.var_name)
195
+ assc.value.kind_of?(LogVarRef) && old_names.include?(assc.value.var_name)
196
196
  end
197
197
  unless keep_assocs.empty?
198
198
  keep_assocs.each { |assc| assc.i_name = new_i_name }
@@ -224,14 +224,14 @@ module MiniKraken
224
224
  end
225
225
  end
226
226
 
227
- # @param var [Variable, VariableRef] the variable to check.
227
+ # @param var [Variable, LogVarRef] the variable to check.
228
228
  # @return [Boolean]
229
229
  def fresh?(var)
230
230
  ground_term = ground_value(var)
231
231
  ground_term.nil? ? true : false
232
232
  end
233
233
 
234
- # @param var [Variable, VariableRef] variable for which the value to retrieve
234
+ # @param var [Variable, LogVarRef] variable for which the value to retrieve
235
235
  # @return [Term, NilClass]
236
236
  def ground_value(var)
237
237
  name = var.respond_to?(:var_name) ? var.var_name : var.name
@@ -260,14 +260,14 @@ module MiniKraken
260
260
  end
261
261
 
262
262
  # Determine whether the reference points to a fresh, bound or ground term.
263
- # @param aVariableRef [VariableRef]
263
+ # @param aVariableRef [LogVarRef]
264
264
  # @return [Freshness]
265
265
  def freshness_ref(aVariableRef)
266
266
  walker = AssociationWalker.new
267
267
  walker.determine_freshness(aVariableRef, self)
268
268
  end
269
269
 
270
- # @param aVariableRef [VariableRef]
270
+ # @param aVariableRef [LogVarRef]
271
271
  # @return [Term, NilClass]
272
272
  def quote_ref(aVariableRef)
273
273
  walker = AssociationWalker.new
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'set'
4
+ require_relative '../atomic/all_atomic'
4
5
  require_relative '../core/any_value'
5
6
  require_relative '../core/conde'
6
7
  require_relative '../core/conj2'
7
- require_relative '../core/cons_cell'
8
+ require_relative '../composite/cons_cell'
8
9
  require_relative '../core/def_relation'
9
10
  require_relative '../core/disj2'
10
11
  require_relative '../core/equals'
@@ -14,10 +15,9 @@ require_relative '../core/formal_ref'
14
15
  require_relative '../glue/fresh_env'
15
16
  require_relative '../glue/fresh_env_factory'
16
17
  require_relative '../core/goal_template'
17
- require_relative '../core/k_boolean'
18
- require_relative '../core/k_symbol'
19
18
  require_relative '../core/succeed'
20
- require_relative '../core/variable_ref'
19
+ require_relative '../core/tap'
20
+ require_relative '../core/log_var_ref'
21
21
  require_relative 'fresh_env'
22
22
  require_relative 'run_star_expression'
23
23
 
@@ -30,7 +30,7 @@ module MiniKraken
30
30
  module DSL
31
31
  # A run* expression tries to find all the solutions
32
32
  # that meet the given goal.
33
- # @return [Core::ConsCell] A list of solutions
33
+ # @return [Composite::ConsCell] A list of solutions
34
34
  def run_star(var_names, goal)
35
35
  program = RunStarExpression.new(var_names, goal)
36
36
  program.run
@@ -61,7 +61,7 @@ module MiniKraken
61
61
 
62
62
  def cons(car_item, cdr_item = nil)
63
63
  tail = cdr_item.nil? ? cdr_item : convert(cdr_item)
64
- Core::ConsCell.new(convert(car_item), tail)
64
+ Composite::ConsCell.new(convert(car_item), tail)
65
65
  end
66
66
 
67
67
  def defrel(relationName, theFormals, &aGoalTemplateExpr)
@@ -107,7 +107,7 @@ module MiniKraken
107
107
  end
108
108
  FreshEnvFactory.new(vars, goal)
109
109
  else
110
- if var_names.kind_of?(String) || var_names.kind_of?(Core::VariableRef)
110
+ if var_names.kind_of?(String) || var_names.kind_of?(Core::LogVarRef)
111
111
  vars = [var_names]
112
112
  else
113
113
  vars = var_names
@@ -121,14 +121,14 @@ module MiniKraken
121
121
  return null if members.empty?
122
122
 
123
123
  head = nil
124
- members.reverse_each { |elem| head = Core::ConsCell.new(convert(elem), head) }
124
+ members.reverse_each { |elem| head = Composite::ConsCell.new(convert(elem), head) }
125
125
 
126
126
  head
127
127
  end
128
128
 
129
129
  # @return [ConsCell] Returns an empty list, that is, a pair whose members are nil.
130
130
  def null
131
- Core::ConsCell.new(nil, nil)
131
+ Composite::ConsCell.new(nil, nil)
132
132
  end
133
133
 
134
134
  # @return [Core::Succeed] A goal that unconditionally succeeds.
@@ -136,6 +136,10 @@ module MiniKraken
136
136
  goal_class.new(Core::Succeed.instance, [])
137
137
  end
138
138
 
139
+ def tap(arg1)
140
+ goal_class.new(Core::Tap.instance, [convert(arg1)])
141
+ end
142
+
139
143
  private
140
144
 
141
145
  def convert(anArgument)
@@ -149,20 +153,20 @@ module MiniKraken
149
153
  any_val.instance_variable_set(:@rank, rank)
150
154
  converted = any_val
151
155
  elsif anArgument.id2name =~ /^"#[ft]"$/
152
- converted = Core::KBoolean.new(anArgument)
156
+ converted = Atomic::KBoolean.new(anArgument)
153
157
  else
154
- converted = Core::KSymbol.new(anArgument)
158
+ converted = Atomic::KSymbol.new(anArgument)
155
159
  end
156
160
  when String
157
161
  if anArgument =~ /^#[ft]$/
158
- converted = Core::KBoolean.new(anArgument)
162
+ converted = Atomic::KBoolean.new(anArgument)
159
163
  else
160
164
  msg = "Internal error: undefined conversion for #{anArgument.class}"
161
165
  raise StandardError, msg
162
166
  end
163
167
  when false, true
164
- converted = Core::KBoolean.new(anArgument)
165
- when Core::KBoolean
168
+ converted = Atomic::KBoolean.new(anArgument)
169
+ when Atomic::KBoolean, Atomic::KSymbol
166
170
  converted = anArgument
167
171
  when Core::FormalRef
168
172
  converted = anArgument
@@ -172,9 +176,9 @@ module MiniKraken
172
176
  converted = anArgument
173
177
  when Core::GoalTemplate
174
178
  converted = anArgument
175
- when Core::VariableRef
179
+ when Core::LogVarRef
176
180
  converted = anArgument
177
- when Core::ConsCell
181
+ when Composite::ConsCell
178
182
  converted = anArgument
179
183
  else
180
184
  msg = "Internal error: undefined conversion for #{anArgument.class}"
@@ -224,7 +228,7 @@ module MiniKraken
224
228
  if @dsl_mode == :defrel && @defrel_formals.include?(name)
225
229
  result = Core::FormalRef.new(name)
226
230
  else
227
- result = Core::VariableRef.new(name)
231
+ result = Core::LogVarRef.new(name)
228
232
  end
229
233
  end
230
234
  end
@@ -3,7 +3,7 @@
3
3
  require_relative '../core/environment'
4
4
  require_relative '../core/conj2'
5
5
  require_relative '../core/goal_template'
6
- require_relative '../core/variable'
6
+ require_relative '../core/log_var'
7
7
 
8
8
  module MiniKraken
9
9
  module Glue
@@ -27,12 +27,17 @@ module MiniKraken
27
27
  super()
28
28
  @goal = valid_goal(aGoal)
29
29
  theNames.each do |nm|
30
- var = Core::Variable.new(nm)
30
+ var = Core::LogVar.new(nm)
31
31
  add_var(var)
32
32
  end
33
33
  @persistent = persistence
34
34
  end
35
35
 
36
+ # @return [Relation] The relation associated with the main goal.
37
+ def relation
38
+ goal.relation
39
+ end
40
+
36
41
  # Attempt to achieve the goal given this environment
37
42
  # @param aParent [Environment]
38
43
  # @return [Fiber<Outcome>] A Fiber object that will generate the results.
@@ -3,7 +3,7 @@
3
3
  require_relative '../core/environment'
4
4
  require_relative '../core/conj2'
5
5
  require_relative '../core/goal_template'
6
- require_relative '../core/variable'
6
+ require_relative '../core/log_var'
7
7
  require_relative 'fresh_env'
8
8
 
9
9
  module MiniKraken
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../core/any_value'
4
- require_relative '../core/cons_cell'
4
+ require_relative '../composite/cons_cell'
5
5
  require_relative 'fresh_env'
6
6
 
7
7
  module MiniKraken
@@ -59,7 +59,7 @@ module MiniKraken
59
59
 
60
60
  new_tail = nil
61
61
  anArray.reverse_each do |elem|
62
- new_tail = Core::ConsCell.new(elem, new_tail)
62
+ new_tail = Composite::ConsCell.new(elem, new_tail)
63
63
  end
64
64
 
65
65
  new_tail
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniKraken
4
- VERSION = '0.2.03'
4
+ VERSION = '0.2.04'
5
5
  end
@@ -2,7 +2,7 @@ inherit_from: ../.rubocop.yml
2
2
 
3
3
  # RSpec expectation lines can be very lenghty
4
4
  Layout/LineLength:
5
- Max: 99
5
+ Max: 90
6
6
 
7
7
  # RSpec contexts can be very lenghty
8
8
  Metrics/BlockLength:
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require 'ostruct'
5
+
6
+ # Load the class under test
7
+ require_relative '../../lib/mini_kraken/atomic/atomic_term'
8
+
9
+ module MiniKraken
10
+ module Atomic
11
+ describe AtomicTerm do
12
+ let(:a_value) { :serenity }
13
+ let(:other_value) { :fuzziness }
14
+ subject { AtomicTerm.new(a_value) }
15
+
16
+ context 'Initialization:' do
17
+ it 'should be created with a Ruby datatype instance' do
18
+ expect { AtomicTerm.new(a_value) }.not_to raise_error
19
+ end
20
+
21
+ it 'knows its value' do
22
+ expect(subject.value).to eq(a_value)
23
+ end
24
+
25
+ it 'freezes its value' do
26
+ expect(subject.value).to be_frozen
27
+ end
28
+ end # context
29
+
30
+ context 'Provided services:' do
31
+ it 'should know that it is a ground term' do
32
+ env = double('mock-env')
33
+ expect(subject.ground?(env)).to be_truthy
34
+ end
35
+
36
+ it 'should know that it is not a fresh term' do
37
+ env = double('mock-env')
38
+ expect(subject.fresh?(env)).to be_falsy
39
+ end
40
+
41
+ it 'should know its freshness' do
42
+ env = double('mock-env')
43
+ expect(subject.freshness(env).degree).to eq(:ground)
44
+ end
45
+
46
+ it 'performs data value comparison' do
47
+ expect(subject == subject).to be_truthy
48
+ expect(subject == subject.value).to be_truthy
49
+
50
+ expect(subject == other_value).to be_falsy
51
+ expect(subject == AtomicTerm.new(other_value)).to be_falsy
52
+
53
+ # Same duck type, same value
54
+ yet_another = OpenStruct.new(value: a_value)
55
+ expect(subject == yet_another).to be_truthy
56
+
57
+ # Same duck type, different value
58
+ still_another = OpenStruct.new(value: other_value)
59
+ expect(subject == still_another).to be_falsy
60
+ end
61
+
62
+ it 'performs type and data value comparison' do
63
+ expect(subject).to be_eql(subject)
64
+
65
+ # Same type, same value
66
+ other = AtomicTerm.new(a_value)
67
+ expect(subject).to be_eql(other)
68
+
69
+ # Same type, other value
70
+ another = AtomicTerm.new(other_value)
71
+ expect(subject).not_to be_eql(another)
72
+
73
+ # Different type, same value
74
+ yet_another = OpenStruct.new(value: other_value)
75
+ expect(subject).not_to be_eql(yet_another)
76
+ end
77
+
78
+ it 'returns itself when receiving quote message' do
79
+ env = double('mock-env')
80
+ expect(subject.quote(env)).to eq(subject)
81
+ end
82
+ end # context
83
+ =begin
84
+ # An atomic term is by definition a ground term: since it doesn't contain
85
+ # any bound variable (in Prolog sense).
86
+ # @param _env [Vocabulary]
87
+ # @return [Freshness]
88
+ def freshness(_env)
89
+ Freshness.new(:ground, self)
90
+ end
91
+ =end
92
+ end # describe
93
+ end # module
94
+ end # module
@@ -4,10 +4,10 @@ require_relative '../spec_helper' # Use the RSpec framework
4
4
  require 'ostruct'
5
5
 
6
6
  # Load the class under test
7
- require_relative '../../lib/mini_kraken/core/k_boolean'
7
+ require_relative '../../lib/mini_kraken/atomic/k_boolean'
8
8
 
9
9
  module MiniKraken
10
- module Core
10
+ module Atomic
11
11
  describe KBoolean do
12
12
  subject { KBoolean.new('#t') }
13
13
 
@@ -28,12 +28,23 @@ module MiniKraken
28
28
  end
29
29
 
30
30
  it 'should know its value' do
31
- expect(subject.value).to eq(true)
32
- end
31
+ other = KBoolean.new(true)
32
+ expect(other.value).to eq(true)
33
+
34
+ other = KBoolean.new('#t')
35
+ expect(other.value).to eq(true)
36
+
37
+ other = KBoolean.new(:"#t")
38
+ expect(other.value).to eq(true)
39
+
40
+ other = KBoolean.new(false)
41
+ expect(other.value).to eq(false)
42
+
43
+ other = KBoolean.new('#f')
44
+ expect(other.value).to eq(false)
33
45
 
34
- it 'should know that it is a ground term' do
35
- env = double('mock-env')
36
- expect(subject.ground?(env)).to be_truthy
46
+ other = KBoolean.new(:"#f")
47
+ expect(other.value).to eq(false)
37
48
  end
38
49
  end # context
39
50
 
@@ -43,27 +54,13 @@ module MiniKraken
43
54
  other = KBoolean.new(true)
44
55
  expect(subject).to be_eql(other)
45
56
 
46
- other = KBoolean.new(:"#t")
47
- expect(subject).to be_eql(other)
48
-
49
- other = KBoolean.new('#t')
50
- expect(subject).to be_eql(other)
51
-
52
57
  # Same type, other value
53
58
  another = KBoolean.new(false)
54
59
  expect(subject).not_to be_eql(another)
55
60
 
56
- # Same type, other value
57
- another = KBoolean.new(:"#f")
58
- expect(subject).not_to be_eql(another)
59
-
60
61
  # Same type, other value
61
62
  another = KBoolean.new('#f')
62
63
  expect(subject).not_to be_eql(another)
63
-
64
- # Different type, same value
65
- yet_another = OpenStruct.new(value: true)
66
- expect(subject).not_to be_eql(yet_another)
67
64
  end
68
65
 
69
66
  it 'should know whether it has same value than other object' do
@@ -71,27 +68,15 @@ module MiniKraken
71
68
  other = KBoolean.new(true)
72
69
  expect(subject == other).to be_truthy
73
70
 
74
- other = KBoolean.new(:"#t")
75
- expect(subject == other).to be_truthy
76
-
77
- other = KBoolean.new('#t')
78
- expect(subject == other).to be_truthy
79
-
80
71
  # Same type, other value
81
72
  another = KBoolean.new(false)
82
73
  expect(subject == another).to be_falsy
83
74
 
84
- another = KBoolean.new(:"#f")
85
- expect(subject == another).to be_falsy
86
-
87
- another = KBoolean.new('#f')
88
- expect(subject == another).to be_falsy
89
-
90
75
  # Same duck type, same value
91
76
  yet_another = OpenStruct.new(value: true)
92
77
  expect(subject == yet_another).to be_truthy
93
78
 
94
- # Different duck type, different value
79
+ # Same duck type, different value
95
80
  still_another = OpenStruct.new(value: false)
96
81
  expect(subject == still_another).to be_falsy
97
82