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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -1
- data/CHANGELOG.md +54 -0
- data/Gemfile +3 -1
- data/README.md +8 -6
- data/Rakefile +5 -3
- data/lib/mini_kraken.rb +3 -1
- data/lib/mini_kraken/core/any_value.rb +9 -7
- data/lib/mini_kraken/core/association.rb +20 -7
- data/lib/mini_kraken/core/association_walker.rb +5 -1
- data/lib/mini_kraken/core/atomic_term.rb +5 -3
- data/lib/mini_kraken/core/binary_relation.rb +8 -6
- data/lib/mini_kraken/core/composite_goal.rb +46 -0
- data/lib/mini_kraken/core/composite_term.rb +7 -20
- data/lib/mini_kraken/core/conj2.rb +76 -0
- data/lib/mini_kraken/core/cons_cell.rb +51 -41
- data/lib/mini_kraken/core/designation.rb +55 -0
- data/lib/mini_kraken/core/disj2.rb +71 -0
- data/lib/mini_kraken/core/duck_fiber.rb +4 -2
- data/lib/mini_kraken/core/environment.rb +25 -11
- data/lib/mini_kraken/core/equals.rb +127 -188
- data/lib/mini_kraken/core/fail.rb +20 -14
- data/lib/mini_kraken/core/freshness.rb +11 -8
- data/lib/mini_kraken/core/goal.rb +8 -4
- data/lib/mini_kraken/core/goal_arg.rb +10 -0
- data/lib/mini_kraken/core/goal_relation.rb +28 -0
- data/lib/mini_kraken/core/k_integer.rb +4 -3
- data/lib/mini_kraken/core/k_symbol.rb +4 -3
- data/lib/mini_kraken/core/nullary_relation.rb +3 -1
- data/lib/mini_kraken/core/outcome.rb +29 -25
- data/lib/mini_kraken/core/relation.rb +4 -18
- data/lib/mini_kraken/core/succeed.rb +20 -14
- data/lib/mini_kraken/core/term.rb +7 -2
- data/lib/mini_kraken/core/variable.rb +11 -25
- data/lib/mini_kraken/core/variable_ref.rb +12 -59
- data/lib/mini_kraken/core/vocabulary.rb +267 -48
- data/lib/mini_kraken/glue/fresh_env.rb +44 -6
- data/lib/mini_kraken/glue/run_star_expression.rb +49 -23
- data/lib/mini_kraken/version.rb +3 -1
- data/mini_kraken.gemspec +15 -13
- data/spec/core/association_spec.rb +4 -4
- data/spec/core/association_walker_spec.rb +25 -24
- data/spec/core/conj2_spec.rb +114 -0
- data/spec/core/cons_cell_spec.rb +12 -3
- data/spec/core/disj2_spec.rb +99 -0
- data/spec/core/duck_fiber_spec.rb +22 -12
- data/spec/core/environment_spec.rb +16 -28
- data/spec/core/equals_spec.rb +7 -7
- data/spec/core/fail_spec.rb +7 -7
- data/spec/core/goal_spec.rb +10 -10
- data/spec/core/k_symbol_spec.rb +5 -6
- data/spec/core/succeed_spec.rb +4 -4
- data/spec/core/variable_ref_spec.rb +0 -4
- data/spec/core/vocabulary_spec.rb +33 -27
- data/spec/glue/fresh_env_spec.rb +28 -2
- data/spec/glue/run_star_expression_spec.rb +370 -59
- data/spec/mini_kraken_spec.rb +4 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/support/factory_methods.rb +20 -2
- 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
|
-
|
6
|
-
module
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
18
|
+
# @return [DuckFiber]
|
19
|
+
def solver_for(_actuals, _env)
|
20
|
+
DuckFiber.new(:failure)
|
21
|
+
end
|
22
|
+
end # class
|
14
23
|
|
15
|
-
|
16
|
-
|
17
|
-
DuckFiber.new(:failure)
|
18
|
-
end
|
19
|
-
end # class
|
24
|
+
Fail.instance.freeze
|
25
|
+
end # module
|
20
26
|
end # module
|
21
|
-
end #
|
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
|
-
|
19
|
+
degree == :fresh
|
18
20
|
end
|
19
21
|
|
20
22
|
def bound?
|
21
|
-
|
23
|
+
degree == :bound
|
22
24
|
end
|
23
25
|
|
24
26
|
def ground?
|
25
|
-
|
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
|
-
|
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 =
|
38
|
+
prefix = 'Invalid goal argument '
|
35
39
|
args.each do |actl|
|
36
|
-
raise StandardError, prefix + actl.to_s unless actl.kind_of?(
|
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,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,35 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'vocabulary'
|
2
4
|
|
3
|
-
|
4
|
-
module
|
5
|
-
|
6
|
-
|
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
|
-
|
9
|
-
|
11
|
+
# @return [Symbol] One of: :"#s" (success), :"#u" (failure)
|
12
|
+
attr_reader :resultant
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
def initialize(aResult, aParent = nil)
|
15
|
+
init_vocabulary(aParent)
|
16
|
+
@resultant = aResult
|
17
|
+
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
def successful?
|
20
|
+
resultant == :"#s"
|
21
|
+
end
|
19
22
|
|
20
|
-
|
21
|
-
|
23
|
+
def ==(other)
|
24
|
+
are_equal = false
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
if resultant == other.resultant && parent == other.parent &&
|
27
|
+
associations == other.associations
|
28
|
+
are_equal = true
|
29
|
+
end
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
+
are_equal
|
32
|
+
end
|
33
|
+
end # class
|
31
34
|
|
32
|
-
|
33
|
-
|
35
|
+
Failure = Outcome.new(:"#u")
|
36
|
+
BasicSuccess = Outcome.new(:"#s")
|
37
|
+
end # module
|
34
38
|
end # module
|
35
|
-
end #
|
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
|
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
|
-
|
6
|
-
module
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
12
|
-
|
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 #
|
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
|
4
|
-
|
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
|
-
|
10
|
-
|
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
|
-
|
15
|
-
|
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
|
28
|
-
|
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
|
-
|
11
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
75
|
-
|
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
|
-
|
82
|
-
|
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
|
-
|
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,
|
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
|