mini_kraken 0.2.03 → 0.2.04

Sign up to get free protection for your applications and to get access to all the features.
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