mini_kraken 0.1.04 → 0.1.09

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -1
  3. data/CHANGELOG.md +54 -0
  4. data/Gemfile +3 -1
  5. data/README.md +8 -6
  6. data/Rakefile +5 -3
  7. data/lib/mini_kraken.rb +3 -1
  8. data/lib/mini_kraken/core/any_value.rb +9 -7
  9. data/lib/mini_kraken/core/association.rb +20 -7
  10. data/lib/mini_kraken/core/association_walker.rb +5 -1
  11. data/lib/mini_kraken/core/atomic_term.rb +5 -3
  12. data/lib/mini_kraken/core/binary_relation.rb +8 -6
  13. data/lib/mini_kraken/core/composite_goal.rb +46 -0
  14. data/lib/mini_kraken/core/composite_term.rb +7 -20
  15. data/lib/mini_kraken/core/conj2.rb +76 -0
  16. data/lib/mini_kraken/core/cons_cell.rb +51 -41
  17. data/lib/mini_kraken/core/designation.rb +55 -0
  18. data/lib/mini_kraken/core/disj2.rb +71 -0
  19. data/lib/mini_kraken/core/duck_fiber.rb +4 -2
  20. data/lib/mini_kraken/core/environment.rb +25 -11
  21. data/lib/mini_kraken/core/equals.rb +127 -188
  22. data/lib/mini_kraken/core/fail.rb +20 -14
  23. data/lib/mini_kraken/core/freshness.rb +11 -8
  24. data/lib/mini_kraken/core/goal.rb +8 -4
  25. data/lib/mini_kraken/core/goal_arg.rb +10 -0
  26. data/lib/mini_kraken/core/goal_relation.rb +28 -0
  27. data/lib/mini_kraken/core/k_integer.rb +4 -3
  28. data/lib/mini_kraken/core/k_symbol.rb +4 -3
  29. data/lib/mini_kraken/core/nullary_relation.rb +3 -1
  30. data/lib/mini_kraken/core/outcome.rb +29 -25
  31. data/lib/mini_kraken/core/relation.rb +4 -18
  32. data/lib/mini_kraken/core/succeed.rb +20 -14
  33. data/lib/mini_kraken/core/term.rb +7 -2
  34. data/lib/mini_kraken/core/variable.rb +11 -25
  35. data/lib/mini_kraken/core/variable_ref.rb +12 -59
  36. data/lib/mini_kraken/core/vocabulary.rb +267 -48
  37. data/lib/mini_kraken/glue/fresh_env.rb +44 -6
  38. data/lib/mini_kraken/glue/run_star_expression.rb +49 -23
  39. data/lib/mini_kraken/version.rb +3 -1
  40. data/mini_kraken.gemspec +15 -13
  41. data/spec/core/association_spec.rb +4 -4
  42. data/spec/core/association_walker_spec.rb +25 -24
  43. data/spec/core/conj2_spec.rb +114 -0
  44. data/spec/core/cons_cell_spec.rb +12 -3
  45. data/spec/core/disj2_spec.rb +99 -0
  46. data/spec/core/duck_fiber_spec.rb +22 -12
  47. data/spec/core/environment_spec.rb +16 -28
  48. data/spec/core/equals_spec.rb +7 -7
  49. data/spec/core/fail_spec.rb +7 -7
  50. data/spec/core/goal_spec.rb +10 -10
  51. data/spec/core/k_symbol_spec.rb +5 -6
  52. data/spec/core/succeed_spec.rb +4 -4
  53. data/spec/core/variable_ref_spec.rb +0 -4
  54. data/spec/core/vocabulary_spec.rb +33 -27
  55. data/spec/glue/fresh_env_spec.rb +28 -2
  56. data/spec/glue/run_star_expression_spec.rb +370 -59
  57. data/spec/mini_kraken_spec.rb +4 -0
  58. data/spec/spec_helper.rb +3 -2
  59. data/spec/support/factory_methods.rb +20 -2
  60. metadata +12 -2
@@ -1,21 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'singleton'
2
4
  require_relative 'duck_fiber'
3
5
  require_relative 'nullary_relation'
4
6
 
5
- module MiniKraken
6
- module Core
7
- # A nullary relation that unconditionally always fails.
8
- class Fail < NullaryRelation
9
- include Singleton
7
+ unless MiniKraken::Core.constants(false).include? :Fail
8
+ module MiniKraken
9
+ module Core
10
+ # A nullary relation that unconditionally always fails.
11
+ class Fail < NullaryRelation
12
+ include Singleton
13
+
14
+ def initialize
15
+ super('fail', '#u')
16
+ end
10
17
 
11
- def initialize
12
- super('fail', '#u')
13
- end
18
+ # @return [DuckFiber]
19
+ def solver_for(_actuals, _env)
20
+ DuckFiber.new(:failure)
21
+ end
22
+ end # class
14
23
 
15
- # @return [DuckFiber]
16
- def solver_for(_actuals, _env)
17
- DuckFiber.new(:failure)
18
- end
19
- end # class
24
+ Fail.instance.freeze
25
+ end # module
20
26
  end # module
21
- end # module
27
+ end # unless
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MiniKraken
2
4
  module Core
3
5
  # Freshness: fresh, bound, ground
@@ -12,31 +14,32 @@ module MiniKraken
12
14
  def initialize(aDegree, anAssociated)
13
15
  super(aDegree, valid_associated(anAssociated))
14
16
  end
15
-
17
+
16
18
  def fresh?
17
- self.degree == :fresh
19
+ degree == :fresh
18
20
  end
19
21
 
20
22
  def bound?
21
- self.degree == :bound
23
+ degree == :bound
22
24
  end
23
25
 
24
26
  def ground?
25
- self.degree == :ground
27
+ degree == :ground
26
28
  end
27
29
 
28
30
  # Does this instance represent something fresh according to
29
31
  # "Reasoned Schemer" book ?
30
32
  def rs_fresh?
31
- self.degree != ground
33
+ degree != ground
32
34
  end
33
-
35
+
34
36
  private
35
-
37
+
36
38
  def valid_associated(anAssociated)
37
39
  raise StandardError, 'Wrong argument' if anAssociated.kind_of?(self.class)
40
+
38
41
  anAssociated
39
42
  end
40
43
  end # struct
41
44
  end # module
42
- end # module
45
+ end # module
@@ -1,8 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'environment'
2
4
 
3
5
  module MiniKraken
6
+ require_relative 'goal_arg'
7
+
4
8
  module Core
5
- class Goal
9
+ class Goal < GoalArg
6
10
  # @return [Relation] The relation corresponding to this goal
7
11
  attr_reader :relation
8
12
 
@@ -31,13 +35,13 @@ module MiniKraken
31
35
  raise StandardError, err_msg
32
36
  end
33
37
 
34
- prefix = "Invalid goal argument "
38
+ prefix = 'Invalid goal argument '
35
39
  args.each do |actl|
36
- raise StandardError, prefix + actl.to_s unless actl.kind_of?(Term)
40
+ raise StandardError, prefix + actl.to_s unless actl.kind_of?(GoalArg)
37
41
  end
38
42
 
39
43
  args.dup
40
44
  end
41
45
  end # class
42
46
  end # module
43
- end # module
47
+ end # module
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniKraken
4
+ module Core
5
+ # The generalization of any iem that can be
6
+ # passed as arugement to a goal.
7
+ class GoalArg
8
+ end # class
9
+ end # module
10
+ end # module
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'relation'
4
+
5
+ module MiniKraken
6
+ module Core
7
+ # A specialization of a relation that accepts only goal(s)
8
+ # as its arguments.
9
+ class GoalRelation < Relation
10
+ def arity
11
+ 2
12
+ end
13
+
14
+ protected
15
+
16
+ def validated_args(actuals)
17
+ actuals.each do |arg|
18
+ unless arg.kind_of?(Goal)
19
+ prefix = "#{name} expects goal as argument, found a "
20
+ raise StandardError, prefix + "'#{arg.class}'"
21
+ end
22
+ end
23
+
24
+ actuals
25
+ end
26
+ end # class
27
+ end # module
28
+ end # module
@@ -1,15 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'atomic_term'
2
4
 
3
5
  module MiniKraken
4
6
  module Core
5
7
  # A specialized atomic term that represents an integer value.
6
- # in MiniKraken
8
+ # in MiniKraken
7
9
  class KInteger < AtomicTerm
8
-
9
10
  # @param aValue [Integer] Ruby representation of integer value
10
11
  def initialize(aValue)
11
12
  super(aValue)
12
13
  end
13
14
  end # class
14
15
  end # module
15
- end # module
16
+ end # module
@@ -1,15 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'atomic_term'
2
4
 
3
5
  module MiniKraken
4
6
  module Core
5
7
  # A specialized atomic term that represents a symbolic value.
6
- # in MiniKraken
8
+ # in MiniKraken
7
9
  class KSymbol < AtomicTerm
8
-
9
10
  # @param aValue [Symbol] Ruby representation of symbol value
10
11
  def initialize(aValue)
11
12
  super(aValue)
12
13
  end
13
14
  end # class
14
15
  end # module
15
- end # module
16
+ end # module
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'relation'
2
4
 
3
5
  module MiniKraken
@@ -17,4 +19,4 @@ module MiniKraken
17
19
  end
18
20
  end # class
19
21
  end # module
20
- end # module
22
+ end # module
@@ -1,35 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'vocabulary'
2
4
 
3
- module MiniKraken
4
- module Core
5
- class Outcome
6
- include Vocabulary # Use mix-in module
5
+ unless MiniKraken::Core.constants(false).include? :Outcome
6
+ module MiniKraken
7
+ module Core
8
+ class Outcome
9
+ include Vocabulary # Use mix-in module
7
10
 
8
- # @return [Symbol] One of: :"#s" (success), :"#u" (failure)
9
- attr_reader :resultant
11
+ # @return [Symbol] One of: :"#s" (success), :"#u" (failure)
12
+ attr_reader :resultant
10
13
 
11
- def initialize(aResult, aParent = nil)
12
- init_vocabulary(aParent)
13
- @resultant = aResult
14
- end
14
+ def initialize(aResult, aParent = nil)
15
+ init_vocabulary(aParent)
16
+ @resultant = aResult
17
+ end
15
18
 
16
- def successful?
17
- self.resultant == :"#s"
18
- end
19
+ def successful?
20
+ resultant == :"#s"
21
+ end
19
22
 
20
- def ==(other)
21
- are_equal = false
23
+ def ==(other)
24
+ are_equal = false
22
25
 
23
- if resultant == other.resultant && parent == other.parent &&
24
- associations == other.associations
25
- are_equal = true
26
- end
26
+ if resultant == other.resultant && parent == other.parent &&
27
+ associations == other.associations
28
+ are_equal = true
29
+ end
27
30
 
28
- are_equal
29
- end
30
- end # class
31
+ are_equal
32
+ end
33
+ end # class
31
34
 
32
- Failure = Outcome.new(:"#u")
33
- BasicSuccess = Outcome.new(:"#s")
35
+ Failure = Outcome.new(:"#u")
36
+ BasicSuccess = Outcome.new(:"#s")
37
+ end # module
34
38
  end # module
35
- end # module
39
+ end # defined
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MiniKraken
2
4
  module Core
3
5
  class Relation
@@ -20,25 +22,9 @@ module MiniKraken
20
22
  raise NotImplementedError
21
23
  end
22
24
 
23
- # Attempt to achieve the goal for a given context (environment)
24
- # @param anEnv [Environment] The context in which the goal take place.
25
- # @return [Fiber<Outcome>] A Fiber object that will generate the results.
26
- # def solve(args, anEnv)
27
- # Fiber instance responds to resume(*args) message
28
- # If too much resume calls => FiberError: dead fiber called message.
29
-
30
- # Fiber.new do |first_yield_arg| do
31
- # begin
32
- # result = relation.solve(actuals, anEnv)
33
- # Fiber.yield result
34
- # while result.success?
35
-
36
- nil
37
- # end
38
-
39
25
  def inspect
40
- alt_name ? alt_name : name
26
+ alt_name || name
41
27
  end
42
28
  end # class
43
29
  end # module
44
- end # module
30
+ end # module
@@ -1,20 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'singleton'
2
4
  require_relative 'duck_fiber'
3
5
  require_relative 'nullary_relation'
4
6
 
5
- module MiniKraken
6
- module Core
7
- # A nullary relation that unconditionally always fails.
8
- class Succeed < NullaryRelation
9
- include Singleton
7
+ unless MiniKraken::Core.constants(false).include? :Succeed
8
+ module MiniKraken
9
+ module Core
10
+ # A nullary relation that unconditionally always fails.
11
+ class Succeed < NullaryRelation
12
+ include Singleton
13
+
14
+ def initialize
15
+ super('succeed', '#s')
16
+ end
17
+
18
+ def solver_for(_actuals, _env)
19
+ DuckFiber.new(:success)
20
+ end
21
+ end # class
10
22
 
11
- def initialize
12
- super('succeed', '#s')
13
- end
14
-
15
- def solver_for(_actuals, _env)
16
- DuckFiber.new(:success)
17
- end
18
- end # class
23
+ Succeed.instance.freeze
24
+ end # module
19
25
  end # module
20
- end # module
26
+ end # unless
@@ -1,7 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'goal_arg'
4
+
1
5
  module MiniKraken
2
6
  module Core
3
- # The generalization of data value in MiniKraken
4
- class Term
7
+ # The generalization of any data value that can be
8
+ # passed as arugement to a goal.
9
+ class Term < GoalArg
5
10
  end # class
6
11
  end # module
7
12
  end # module
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'designation'
1
4
  require_relative 'any_value'
2
5
  require_relative 'vocabulary'
3
6
 
@@ -6,26 +9,19 @@ module MiniKraken
6
9
  # Representation of a MiniKraken variable.
7
10
  # It is a named slot that can be associated with one value.
8
11
  class Variable
9
- # @return [String] Name of the variable
10
- attr_reader :name
12
+ include Designation # Mixin: Acquire name attribute
13
+
14
+ # @return [String] Internal variable name used by MiniKraken
15
+ attr_accessor :i_name
11
16
 
12
17
  # @param aName [String] The name of the variable
13
18
  def initialize(aName)
14
- @name = valid_name(aName)
15
- end
16
-
17
- def fresh?(anEnvironment)
18
- anEnvironment.fresh?(self)
19
- end
20
-
21
- # @param env [Environment]
22
- # @return [Freshness]
23
- def freshness(env)
24
- freshness = env.freshness_ref(self)
19
+ init_designation(aName)
20
+ @i_name = name.dup
25
21
  end
26
22
 
27
- def ground?(anEnvironment)
28
- !fresh?(anEnvironment)
23
+ def fused?
24
+ name != i_name
29
25
  end
30
26
 
31
27
  def quote(anEnvironment)
@@ -34,16 +30,6 @@ module MiniKraken
34
30
  val = anEnvironment.quote_ref(self)
35
31
  val.nil? ? AnyValue.new(name, anEnvironment) : val
36
32
  end
37
-
38
- private
39
-
40
- def valid_name(aName)
41
- if aName.empty?
42
- raise StandardError, "Variable name may not be empty."
43
- end
44
-
45
- aName
46
- end
47
33
  end # class
48
34
  end # module
49
35
  end # module
@@ -1,44 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'term'
2
4
  require_relative 'any_value'
3
- require_relative 'association'
4
5
 
5
6
  module MiniKraken
6
7
  module Core
7
8
  # A variable reference represents the occurrence of a variable (name) in a
8
9
  # MiniKraken term.
9
10
  class VariableRef < Term
10
- # @return [String] Name of the variable
11
- attr_reader :var_name
11
+ include Designation # Mixin: Acquire name attribute
12
+ alias var_name name
12
13
 
13
14
  # @param aName [String] The name of the variable
14
15
  def initialize(aName)
15
- @var_name = valid_name(aName)
16
- end
17
-
18
- # @param env [Environment]
19
- # @return [Boolean]
20
- def fresh?(env)
21
- env.fresh?(self)
22
- end
23
-
24
- # @param env [Environment]
25
- # @return [Boolean]
26
- def bound?(env)
27
- freshness = env.freshness_ref(self)
28
- freshness.degree == :bound
29
- end
30
-
31
- # @param env [Environment]
32
- # @return [Boolean]
33
- def ground?(env)
34
- !fresh?(env)
16
+ init_designation(aName)
35
17
  end
36
18
 
37
19
  # @param aValue [Term]
38
20
  # @param env [Environment]
39
21
  def associate(aValue, env)
40
- assoc = Association.new(var_name, aValue)
41
- env.add_assoc(assoc)
22
+ env.add_assoc(var_name, aValue)
42
23
  end
43
24
 
44
25
  # @param env [Environment]
@@ -54,13 +35,6 @@ module MiniKraken
54
35
  freshness.associated
55
36
  end
56
37
 
57
- # @param env [Environment]
58
- # @return [Freshness]
59
- def freshness(env)
60
- freshness = env.freshness_ref(self)
61
- end
62
-
63
-
64
38
  # @param env [Environment]
65
39
  def quote(env)
66
40
  val = env.quote_ref(self)
@@ -71,34 +45,15 @@ module MiniKraken
71
45
  # @param env [Environment]
72
46
  # @return [Boolean]
73
47
  def fused_with?(another, env)
74
- # I should point to 'another'...
75
- other_name = another.var_name
76
- to_another = values(env).find do |val|
77
- val.kind_of?(VariableRef) && val.var_name == other_name
78
- end
79
- return false unless to_another
48
+ my_var = env.name2var(var_name)
49
+ return false unless my_var.fused?
80
50
 
81
- # 'another' should point to me
82
- to_me = another.values(env).find do |val|
83
- val.kind_of?(VariableRef) && val.var_name == var_name
84
- end
85
- !to_me.nil?
51
+ other_var = env.name2var(another.var_name)
52
+ return my_var.i_name == other_var.i_name
86
53
  end
87
54
 
88
55
  def names_fused(env)
89
- to_others = values(env).select do |val|
90
- val.kind_of?(VariableRef)
91
- end
92
- return [] if to_others.empty?
93
-
94
- # 'others' should point to me
95
- to_me = to_others.select do |other|
96
- other.values(env).find do |val|
97
- val.kind_of?(VariableRef) && val.var_name == var_name
98
- end
99
- end
100
-
101
- to_me.map { |other| other.var_name }
56
+ env.names_fused(var_name)
102
57
  end
103
58
 
104
59
  # param another [VariableRef]
@@ -112,13 +67,11 @@ module MiniKraken
112
67
 
113
68
  def valid_name(aName)
114
69
  if aName.empty?
115
- raise StandardError, "Variable name may not be empty."
70
+ raise StandardError, 'Variable name may not be empty.'
116
71
  end
117
72
 
118
73
  aName
119
74
  end
120
-
121
-
122
75
  end # class
123
76
  end # module
124
77
  end # module