mini_kraken 0.1.05 → 0.1.10

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -1
  3. data/CHANGELOG.md +56 -0
  4. data/README.md +5 -3
  5. data/lib/mini_kraken/core/composite_goal.rb +46 -0
  6. data/lib/mini_kraken/core/composite_term.rb +2 -0
  7. data/lib/mini_kraken/core/conj2.rb +79 -0
  8. data/lib/mini_kraken/core/cons_cell.rb +49 -43
  9. data/lib/mini_kraken/core/designation.rb +55 -0
  10. data/lib/mini_kraken/core/disj2.rb +71 -0
  11. data/lib/mini_kraken/core/duck_fiber.rb +1 -1
  12. data/lib/mini_kraken/core/environment.rb +1 -1
  13. data/lib/mini_kraken/core/equals.rb +134 -132
  14. data/lib/mini_kraken/core/fail.rb +18 -14
  15. data/lib/mini_kraken/core/goal.rb +4 -2
  16. data/lib/mini_kraken/core/goal_arg.rb +10 -0
  17. data/lib/mini_kraken/core/goal_relation.rb +28 -0
  18. data/lib/mini_kraken/core/outcome.rb +40 -24
  19. data/lib/mini_kraken/core/succeed.rb +17 -13
  20. data/lib/mini_kraken/core/term.rb +5 -2
  21. data/lib/mini_kraken/core/variable.rb +3 -27
  22. data/lib/mini_kraken/core/variable_ref.rb +3 -28
  23. data/lib/mini_kraken/core/vocabulary.rb +39 -19
  24. data/lib/mini_kraken/glue/fresh_env.rb +45 -3
  25. data/lib/mini_kraken/glue/run_star_expression.rb +44 -19
  26. data/lib/mini_kraken/version.rb +1 -1
  27. data/spec/core/conj2_spec.rb +114 -0
  28. data/spec/core/cons_cell_spec.rb +8 -0
  29. data/spec/core/disj2_spec.rb +99 -0
  30. data/spec/core/duck_fiber_spec.rb +12 -1
  31. data/spec/core/equals_spec.rb +3 -3
  32. data/spec/core/outcome_spec.rb +48 -0
  33. data/spec/core/vocabulary_spec.rb +11 -5
  34. data/spec/glue/fresh_env_spec.rb +27 -1
  35. data/spec/glue/run_star_expression_spec.rb +478 -53
  36. data/spec/mini_kraken_spec.rb +2 -0
  37. data/spec/spec_helper.rb +0 -1
  38. data/spec/support/factory_methods.rb +16 -0
  39. metadata +14 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4ce5f0f43f5e84f377cf90e2ed49d6ff54de93b66641655fb41dd6b8feef277
4
- data.tar.gz: 2081e486f8beba0b0073461464c632fa63af83cec27a48fb3d84c1a972b821f9
3
+ metadata.gz: ec7b984a9f0c857f74c8a8989c5da2072398775573b7ca6679d99f96ef13eac1
4
+ data.tar.gz: cdebdebae82c424b9ae701f959765f0905322798a371e2aec42ed9a229e35a4f
5
5
  SHA512:
6
- metadata.gz: ea0580c9219f1a1fd586d024f06e11cf6dd1f979182c6f5a15473c65b78fa7244ba01ca9191f31e73de78b20d7aa88c60d86afa1207dbaab246c64c6650f0d1f
7
- data.tar.gz: 9af43ee21606cac23d2512002491d0264fcbc7a74b9974edbd70c23f4bcbf25c7cc7010845aad88dee2d507a1f6d070dd402cd9a6f2abe0234999617b3ae7b68
6
+ metadata.gz: 2ce3553527adeebef7adc69ec5a861fe65f9f451e54a81e23f00769923ced6b6a6011846ae3e9a673c8b9094a7dcce6ea6f8d263d55c8f543ef0de309e34c11c
7
+ data.tar.gz: 90b45061cde1119ad648359063682f411f9e5705a294340976bd027561b1d94da7afbfc9d0d27dce67942e1407d4d4ea40df85cf3fe67c9fca998d22052b6187
@@ -3,5 +3,9 @@ sudo: false
3
3
  language: ruby
4
4
  cache: bundler
5
5
  rvm:
6
- - 2.6.3
6
+ - 2.7.1
7
+ - 2.6.6
8
+ - 2.5.8
9
+ - 2.4.10
10
+ - jruby-head
7
11
  before_install: gem install bundler -v 2.0.2
@@ -1,3 +1,59 @@
1
+ ## [0.1.10] - 2020-06-10
2
+ - Supports frames from "The Reasoned Scheme" book up to frame [1:81]
3
+
4
+ ### New
5
+ - Factory methods `Outcome#failure`, `Outcome#success`
6
+ - Method `Vocabulary#inspect`
7
+ - File `outcome_spec.rb`
8
+
9
+ ### FIXED
10
+ - `Conj2#conjunction` vocabulary wasn't cleared when outcome2 was nil.
11
+
12
+ ## [0.1.09] - 2020-06-06
13
+ - Supports frames from "The Reasoned Scheme" book up to frame [1:76]
14
+
15
+ ### CHANGED
16
+ - Method `FreshEnv#initialize`accepts an array of goals as second argument. This array is transformed into a conjunction of goals.
17
+ - Method `RunStarExpression#initialize` accepts multiple multiple variable names and goals.
18
+ - Method `RunStarExpression#run` can handle solutions with multiple variables.
19
+
20
+ ## [0.1.08] - 2020-05-30
21
+ - Fix of nasty bug (object aliasing) that caused flaky failures in specs.
22
+
23
+ ### FIXED
24
+ - `DuckFiber#resume` each call returns a distinct `Outcome` instance when successful.
25
+
26
+ ## [0.1.07] - 2020-05-23
27
+ - Implementation of `disj2` (two arguments disjunction - or -)
28
+
29
+ ### New
30
+ - Class `Disj2` as subclass of `GoalRelation` that implements the disjunction of two subgoals
31
+
32
+ ### CHANGED
33
+ - Class `Disj2`: common code with `Conj2` class factored out to superclass `GoalRelation`
34
+ - File `cons_cell.rb`: prevent multiple inclusions via different requires
35
+ - Method `Vocabulary#ancestor_walker` now returns an `Enumerator` instead of a `Fiber`.
36
+
37
+ ### FIXED
38
+ - Method `RunStarExpression#run` clear associations and rankings for second and consecutive solmutions
39
+
40
+
41
+ ## [0.1.06] - 2020-05-20
42
+ - Implementation of `conj2` (two arguments conjunction - and -)
43
+
44
+ ### New
45
+ - Class `CompositeGoal`
46
+ - Class `Conj2` as subclass of `GoalRelation` that implements the conjunction of two subgoals
47
+ - Mixin module `Designation` to factor out the common methods in `Variable` and `VariableRef` classes
48
+ - Class `GoalArg` abstract class, that is a generalization for anything that be be argument of a goal.
49
+ - Class `GoalRelation` as subclass of `Relation`. A goal that is linked to a such relation may have goals as its arguments only.
50
+
51
+ ### Changed
52
+ - Class `Goal` is new subclass of class `GoalArg`. Therefore a goal can be an argument to another goal.
53
+ - Class `Term` is new subclass of class `GoalArg`. Therefore a term can be an argument of a goal.
54
+ - Classes `Variable`, `VariableRef` now include mix-in module `Designation`
55
+ - File `cd_implementation.txt` Updated with changes of class relationship
56
+
1
57
  ## [0.1.05] - 2020-05-09
2
58
  - Changed implementation of fused variables
3
59
  - Magic comments for frozen string literal
data/README.md CHANGED
@@ -13,12 +13,14 @@ ISBN: 9780262535519, (2018), MIT Press.
13
13
  ### Features
14
14
  - [X] ==
15
15
  - [X] run\*
16
- - [X] fresh
16
+ - [X] fresh
17
+ - [X] conj2
18
+ - [X] disj2
17
19
 
18
20
  ### TODO
19
- - [ ] disj2
20
- - [ ] conj2
21
+ - [ ] defrel
21
22
  - [ ] conde
23
+ - [ ] Occurs check
22
24
 
23
25
  ## Installation
24
26
 
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'environment'
4
+
5
+ module MiniKraken
6
+ module Core
7
+ class CompositeGoal
8
+ # @return [Operator] The operator corresponding to this goal
9
+ attr_reader :operator
10
+
11
+ # @return [Array<Goal>] The child goals (sub-goals)
12
+ attr_reader :children
13
+
14
+ # @param anOperator [Operator] The operator corresponding to this goal
15
+ # @param theChildren [Array<Goal>] The child goals (sub-goals)
16
+ def initialize(anOperator, theChildren)
17
+ @operator = anOperator
18
+ @children = validated_children(theChildren)
19
+ end
20
+
21
+ # Attempt to achieve the goal for a given context (environment)
22
+ # @param anEnv [Environment] The context in which the goal take place.
23
+ # @return [Fiber<Outcome>] A Fiber object that will generate the results.
24
+ def attain(anEnv)
25
+ operator.solver_for(children, anEnv)
26
+ end
27
+
28
+ private
29
+
30
+ def validated_children(theChildren)
31
+ my_arity = operator.arity
32
+ if args.size != my_arity
33
+ err_msg = "Goal has #{theChildren.size} arguments, expected #{my_arity}"
34
+ raise StandardError, err_msg
35
+ end
36
+
37
+ prefix = 'Invalid goal argument '
38
+ theChildren.each do |subg|
39
+ raise StandardError, prefix + subg.to_s unless subg.kind_of?(Goal)
40
+ end
41
+
42
+ theChildren.dup
43
+ end
44
+ end # class
45
+ end # module
46
+ end # module
@@ -8,6 +8,8 @@ module MiniKraken
8
8
  # An composite term is an Minikraken term that can be
9
9
  # decomposed into simpler MiniKraken data value(s).
10
10
  class CompositeTerm < Term
11
+ # Abstract method (to override). Return the child terms.
12
+ # @return [Array<Term>]
11
13
  def children
12
14
  raise NotImplementedError, 'This method must re-defined in subclass(es).'
13
15
  end
@@ -0,0 +1,79 @@
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
+ unless MiniKraken::Core.constants(false).include? :Conj2
10
+ module MiniKraken
11
+ module Core
12
+ # The conjunction is a relation that accepts only goal(s) as its two
13
+ # arguments. It succeeds if and only both its goal arguments succeeds.
14
+ class Conj2 < GoalRelation
15
+ include Singleton
16
+
17
+ def initialize
18
+ super('conj2', nil)
19
+ end
20
+
21
+ # @param actuals [Array<Term>] A two-elements array
22
+ # @param anEnv [Vocabulary] A vocabulary object
23
+ # @return [Fiber<Outcome>] A Fiber that yields Outcomes objects
24
+ def solver_for(actuals, anEnv)
25
+ g1, g2 = *validated_args(actuals)
26
+ Fiber.new { conjunction(g1, g2, anEnv) }
27
+ end
28
+
29
+ # Yields [Outcome, NilClass] result of the conjunction
30
+ # @param g1 [Goal] First goal argument
31
+ # @param g2 [Goal] Second goal argument
32
+ # @param voc [Vocabulary] A vocabulary object
33
+ def conjunction(g1, g2, voc)
34
+ # require 'debug'
35
+ if g1.relation.kind_of?(Fail) || g2.relation.kind_of?(Fail)
36
+ Fiber.yield Outcome.new(:"#u", voc)
37
+ else
38
+ outcome1 = nil
39
+ outcome2 = nil
40
+ f1 = g1.attain(voc)
41
+ loop do
42
+ outcome1 = f1.resume
43
+ break unless outcome1
44
+
45
+ outcome1.parent = voc unless outcome1.parent
46
+ if outcome1.successful?
47
+ f2 = g2.attain(outcome1)
48
+ loop do
49
+ outcome2 = f2.resume
50
+ break unless outcome2
51
+
52
+ outcome2.parent = voc unless outcome2.parent
53
+ if outcome2.successful?
54
+ res = Outcome.new(:"#s", voc)
55
+ res.merge(outcome1)
56
+ res.merge(outcome2)
57
+ Fiber.yield res
58
+ else
59
+ Fiber.yield outcome2
60
+ end
61
+ outcome2.clear
62
+ end
63
+ else
64
+ Fiber.yield outcome1
65
+ end
66
+ if outcome1.successful? && (outcome2&.successful? || outcome2.nil?)
67
+ voc.clear
68
+ end
69
+ end
70
+ end
71
+
72
+ Fiber.yield nil
73
+ end
74
+ end # class
75
+
76
+ Conj2.instance.freeze
77
+ end # module
78
+ end # module
79
+ end # unless
@@ -2,47 +2,53 @@
2
2
 
3
3
  require_relative 'composite_term'
4
4
 
5
- module MiniKraken
6
- module Core
7
- class ConsCell < CompositeTerm
8
- attr_reader :car
9
- attr_reader :cdr
10
-
11
- def initialize(obj1, obj2 = nil)
12
- @car = obj1
13
- @cdr = obj2
14
- end
15
-
16
- def children
17
- [car, cdr]
18
- end
19
-
20
- # Return true if it is an empty list, otherwise false.
21
- # A list is empty, when both car and cdr fields are nil.
22
- def null?
23
- car.nil? && cdr.nil?
24
- end
25
-
26
- def ==(other)
27
- return false unless other.respond_to?(:car)
28
-
29
- (car == other.car) && (cdr == other.cdr)
30
- end
31
-
32
- def eql?(other)
33
- (self.class == other.class) && car.eql?(other.car) && cdr.eql?(other.cdr)
34
- end
35
-
36
- def quote(anEnv)
37
- return self if null?
38
-
39
- new_car = car.nil? ? nil : car.quote(anEnv)
40
- new_cdr = cdr.nil? ? nil : cdr.quote(anEnv)
41
- ConsCell.new(new_car, new_cdr)
42
- end
43
- end # class
44
-
45
- # Constant representing the null (empty) list.
46
- NullList = ConsCell.new(nil, nil).freeze
5
+ unless MiniKraken::Core.constants(false).include? :ConsCell
6
+ module MiniKraken
7
+ module Core
8
+ class ConsCell < CompositeTerm
9
+ attr_reader :car
10
+ attr_reader :cdr
11
+
12
+ def initialize(obj1, obj2 = nil)
13
+ @car = obj1
14
+ @cdr = obj2
15
+ end
16
+
17
+ def children
18
+ [car, cdr]
19
+ end
20
+
21
+ # Return true if it is an empty list, otherwise false.
22
+ # A list is empty, when both car and cdr fields are nil.
23
+ def null?
24
+ car.nil? && cdr.nil?
25
+ end
26
+
27
+ def ==(other)
28
+ return false unless other.respond_to?(:car)
29
+
30
+ (car == other.car) && (cdr == other.cdr)
31
+ end
32
+
33
+ def eql?(other)
34
+ (self.class == other.class) && car.eql?(other.car) && cdr.eql?(other.cdr)
35
+ end
36
+
37
+ def quote(anEnv)
38
+ return self if null?
39
+
40
+ new_car = car.nil? ? nil : car.quote(anEnv)
41
+ new_cdr = cdr.nil? ? nil : cdr.quote(anEnv)
42
+ ConsCell.new(new_car, new_cdr)
43
+ end
44
+
45
+ def append(another)
46
+ @cdr = another
47
+ end
48
+ end # class
49
+
50
+ # Constant representing the null (empty) list.
51
+ NullList = ConsCell.new(nil, nil).freeze
52
+ end # module
47
53
  end # module
48
- end # module
54
+ end # defined
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniKraken
4
+ module Core
5
+ # Wordnet definition: Identifying word or words by which someone or
6
+ # something is called and classified or distinguished from others.
7
+ # Mix-in module that contains factored code for managing named entries
8
+ # in a vocabulary such as variables and variable references.
9
+ module Designation
10
+ # @return [String] User-defined name of the variable
11
+ attr_reader :name
12
+
13
+ def init_designation(aName)
14
+ @name = valid_name(aName)
15
+ end
16
+
17
+ # @param voc [Vocabulary]
18
+ # @return [Freshness]
19
+ def freshness(voc)
20
+ voc.freshness_ref(self)
21
+ end
22
+
23
+ # @param voc [Vocabulary]
24
+ # @return [Boolean]
25
+ def fresh?(voc)
26
+ frsh = freshness(voc)
27
+ frsh.degree == :fresh || frsh.degree == :bound
28
+ end
29
+
30
+ # @param voc [Vocabulary]
31
+ # @return [Boolean]
32
+ def bound?(voc)
33
+ frsh = freshness(voc)
34
+ frsh.degree == :bound
35
+ end
36
+
37
+ # @param voc [Vocabulary]
38
+ # @return [Boolean]
39
+ def ground?(voc)
40
+ frsh = freshness(voc)
41
+ frsh.degree == :bound
42
+ end
43
+
44
+ private
45
+
46
+ def valid_name(aName)
47
+ if aName.empty?
48
+ raise StandardError, 'Variable name may not be empty.'
49
+ end
50
+
51
+ aName
52
+ end
53
+ end # class
54
+ end # module
55
+ end # module
@@ -0,0 +1,71 @@
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
+ unless MiniKraken::Core.constants(false).include? :Disj2
10
+ module MiniKraken
11
+ module Core
12
+ # The disjunction is a relation that accepts only goal(s) as its two
13
+ # arguments. It succeeds if at least one of its goal arguments succeeds.
14
+ class Disj2 < GoalRelation
15
+ include Singleton
16
+
17
+ def initialize
18
+ super('disj2', nil)
19
+ end
20
+
21
+ # @param actuals [Array<Term>] A two-elements array
22
+ # @param anEnv [Vocabulary] A vocabulary object
23
+ # @return [Fiber<Outcome>] A Fiber that yields Outcomes objects
24
+ def solver_for(actuals, anEnv)
25
+ g1, g2 = *validated_args(actuals)
26
+ Fiber.new { disjunction(g1, g2, anEnv) }
27
+ end
28
+
29
+ # Yields [Outcome, NilClass] result of the disjunction
30
+ # @param g1 [Goal] First goal argument
31
+ # @param g2 [Goal] Second goal argument
32
+ # @param voc [Vocabulary] A vocabulary object
33
+ def disjunction(g1, g2, voc)
34
+ # require 'debug'
35
+ outcome1 = nil
36
+ outcome2 = nil
37
+ if g1.relation.kind_of?(Fail) && g2.relation.kind_of?(Fail)
38
+ Fiber.yield Outcome.new(:"#u", voc)
39
+ else
40
+ f1 = g1.attain(voc)
41
+ loop do
42
+ outcome1 = f1.resume
43
+ break unless outcome1
44
+
45
+ outcome1.parent = voc unless outcome1.parent
46
+ if outcome1.successful?
47
+ Fiber.yield outcome1
48
+ outcome1.clear
49
+ end
50
+ end
51
+ f2 = g2.attain(voc)
52
+ loop do
53
+ outcome2 = f2.resume
54
+ break unless outcome2
55
+
56
+ outcome2.parent = voc unless outcome2.parent
57
+ if outcome2.successful?
58
+ Fiber.yield outcome2
59
+ outcome2.clear
60
+ end
61
+ end
62
+ end
63
+
64
+ Fiber.yield nil
65
+ end
66
+ end # class
67
+
68
+ Disj2.instance.freeze
69
+ end # module
70
+ end # module
71
+ end # unless