mini_kraken 0.2.03 → 0.3.03
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/.rubocop.yml +378 -333
- data/CHANGELOG.md +48 -0
- data/README.md +29 -21
- data/lib/mini_kraken/atomic/all_atomic.rb +5 -0
- data/lib/mini_kraken/atomic/atomic_term.rb +96 -0
- data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
- data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -5
- data/lib/mini_kraken/atomic/k_string.rb +17 -0
- data/lib/mini_kraken/{core → atomic}/k_symbol.rb +4 -8
- data/lib/mini_kraken/composite/all_composite.rb +4 -0
- data/lib/mini_kraken/composite/composite_term.rb +27 -0
- data/lib/mini_kraken/composite/cons_cell.rb +301 -0
- data/lib/mini_kraken/composite/cons_cell_visitor.rb +50 -0
- data/lib/mini_kraken/composite/list.rb +32 -0
- data/lib/mini_kraken/core/all_core.rb +8 -0
- data/lib/mini_kraken/core/any_value.rb +31 -7
- data/lib/mini_kraken/core/arity.rb +69 -0
- data/lib/mini_kraken/core/association.rb +29 -4
- data/lib/mini_kraken/core/association_copy.rb +50 -0
- data/lib/mini_kraken/core/base_term.rb +13 -0
- data/lib/mini_kraken/core/blackboard.rb +315 -0
- data/lib/mini_kraken/core/bookmark.rb +46 -0
- data/lib/mini_kraken/core/context.rb +492 -0
- data/lib/mini_kraken/core/duck_fiber.rb +21 -19
- data/lib/mini_kraken/core/entry.rb +40 -0
- data/lib/mini_kraken/core/fail.rb +20 -18
- data/lib/mini_kraken/core/fusion.rb +29 -0
- data/lib/mini_kraken/core/goal.rb +20 -29
- data/lib/mini_kraken/core/log_var.rb +22 -0
- data/lib/mini_kraken/core/log_var_ref.rb +108 -0
- data/lib/mini_kraken/core/nullary_relation.rb +2 -9
- data/lib/mini_kraken/core/parametrized_term.rb +68 -0
- data/lib/mini_kraken/core/relation.rb +14 -28
- data/lib/mini_kraken/core/scope.rb +67 -0
- data/lib/mini_kraken/core/solver_adapter.rb +58 -0
- data/lib/mini_kraken/core/specification.rb +48 -0
- data/lib/mini_kraken/core/succeed.rb +21 -17
- data/lib/mini_kraken/core/symbol_table.rb +137 -0
- data/lib/mini_kraken/core/term.rb +15 -4
- data/lib/mini_kraken/glue/dsl.rb +44 -88
- data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
- data/lib/mini_kraken/rela/all_rela.rb +8 -0
- data/lib/mini_kraken/rela/binary_relation.rb +30 -0
- data/lib/mini_kraken/rela/conde.rb +143 -0
- data/lib/mini_kraken/rela/conj2.rb +65 -0
- data/lib/mini_kraken/rela/def_relation.rb +93 -0
- data/lib/mini_kraken/rela/disj2.rb +70 -0
- data/lib/mini_kraken/rela/fresh.rb +98 -0
- data/lib/mini_kraken/{core → rela}/goal_relation.rb +7 -9
- data/lib/mini_kraken/rela/unify.rb +265 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/mini_kraken.gemspec +2 -2
- data/spec/.rubocop.yml +1 -1
- data/spec/atomic/atomic_term_spec.rb +98 -0
- data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
- data/spec/{core → atomic}/k_symbol_spec.rb +3 -16
- data/spec/composite/cons_cell_spec.rb +225 -0
- data/spec/{core → composite}/cons_cell_visitor_spec.rb +36 -20
- data/spec/composite/list_spec.rb +50 -0
- data/spec/core/any_value_spec.rb +52 -0
- data/spec/core/arity_spec.rb +92 -0
- data/spec/core/association_copy_spec.rb +69 -0
- data/spec/core/association_spec.rb +31 -4
- data/spec/core/blackboard_spec.rb +287 -0
- data/spec/core/bookmark_spec.rb +40 -0
- data/spec/core/context_spec.rb +245 -0
- data/spec/core/core_spec.rb +40 -0
- data/spec/core/duck_fiber_spec.rb +16 -46
- data/spec/core/fail_spec.rb +5 -6
- data/spec/core/goal_spec.rb +22 -12
- data/spec/core/log_var_ref_spec.rb +105 -0
- data/spec/core/log_var_spec.rb +64 -0
- data/spec/core/nullary_relation_spec.rb +33 -0
- data/spec/core/parametrized_tem_spec.rb +39 -0
- data/spec/core/relation_spec.rb +33 -0
- data/spec/core/scope_spec.rb +73 -0
- data/spec/core/solver_adapter_spec.rb +70 -0
- data/spec/core/specification_spec.rb +43 -0
- data/spec/core/succeed_spec.rb +5 -5
- data/spec/core/symbol_table_spec.rb +142 -0
- data/spec/glue/dsl_chap1_spec.rb +88 -144
- data/spec/glue/dsl_chap2_spec.rb +454 -19
- data/spec/glue/run_star_expression_spec.rb +81 -906
- data/spec/rela/conde_spec.rb +153 -0
- data/spec/rela/conj2_spec.rb +123 -0
- data/spec/rela/def_relation_spec.rb +119 -0
- data/spec/rela/disj2_spec.rb +117 -0
- data/spec/rela/fresh_spec.rb +147 -0
- data/spec/rela/unify_spec.rb +369 -0
- data/spec/support/factory_atomic.rb +29 -0
- data/spec/support/factory_composite.rb +21 -0
- data/spec/support/factory_methods.rb +11 -26
- metadata +98 -70
- data/lib/mini_kraken/core/association_walker.rb +0 -183
- data/lib/mini_kraken/core/atomic_term.rb +0 -67
- data/lib/mini_kraken/core/base_arg.rb +0 -10
- data/lib/mini_kraken/core/binary_relation.rb +0 -63
- data/lib/mini_kraken/core/composite_goal.rb +0 -46
- data/lib/mini_kraken/core/composite_term.rb +0 -41
- data/lib/mini_kraken/core/conde.rb +0 -143
- data/lib/mini_kraken/core/conj2.rb +0 -79
- data/lib/mini_kraken/core/cons_cell.rb +0 -82
- data/lib/mini_kraken/core/cons_cell_visitor.rb +0 -102
- data/lib/mini_kraken/core/def_relation.rb +0 -53
- data/lib/mini_kraken/core/designation.rb +0 -55
- data/lib/mini_kraken/core/disj2.rb +0 -72
- data/lib/mini_kraken/core/environment.rb +0 -73
- data/lib/mini_kraken/core/equals.rb +0 -193
- data/lib/mini_kraken/core/formal_arg.rb +0 -22
- data/lib/mini_kraken/core/formal_ref.rb +0 -25
- data/lib/mini_kraken/core/freshness.rb +0 -45
- data/lib/mini_kraken/core/goal_arg.rb +0 -12
- data/lib/mini_kraken/core/goal_template.rb +0 -102
- data/lib/mini_kraken/core/k_boolean.rb +0 -35
- data/lib/mini_kraken/core/outcome.rb +0 -63
- data/lib/mini_kraken/core/variable.rb +0 -41
- data/lib/mini_kraken/core/variable_ref.rb +0 -84
- data/lib/mini_kraken/core/vocabulary.rb +0 -446
- data/lib/mini_kraken/glue/fresh_env.rb +0 -103
- data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
- data/spec/core/association_walker_spec.rb +0 -192
- data/spec/core/conde_spec.rb +0 -147
- data/spec/core/conj2_spec.rb +0 -114
- data/spec/core/cons_cell_spec.rb +0 -107
- data/spec/core/def_relation_spec.rb +0 -97
- data/spec/core/disj2_spec.rb +0 -99
- data/spec/core/environment_spec.rb +0 -142
- data/spec/core/equals_spec.rb +0 -317
- data/spec/core/goal_template_spec.rb +0 -74
- data/spec/core/outcome_spec.rb +0 -56
- data/spec/core/variable_ref_spec.rb +0 -30
- data/spec/core/variable_spec.rb +0 -35
- data/spec/core/vocabulary_spec.rb +0 -219
- data/spec/glue/fresh_env_factory_spec.rb +0 -97
- data/spec/glue/fresh_env_spec.rb +0 -62
@@ -1,34 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../core/
|
4
|
-
require_relative '../
|
5
|
-
require_relative '
|
3
|
+
require_relative '../core/context'
|
4
|
+
require_relative '../composite/list'
|
5
|
+
require_relative '../rela/fresh'
|
6
6
|
|
7
7
|
module MiniKraken
|
8
8
|
module Glue
|
9
9
|
class RunStarExpression
|
10
|
-
# @return [
|
11
|
-
|
10
|
+
# @return [Core::Context] The context in which run* variables
|
11
|
+
# will be evaluated.
|
12
|
+
attr_reader :ctx
|
13
|
+
|
14
|
+
# @return [Core::Goal] The main goal to satisfy
|
15
|
+
attr_reader :goal
|
12
16
|
|
13
17
|
# @param var_names [String, Array<String>] One variable name or an array of names
|
14
|
-
# @param
|
15
|
-
def initialize(var_names,
|
16
|
-
|
17
|
-
|
18
|
+
# @param aGoal [Core::Goal, Array<Core::Goal>] A single goal or an array of goals to conjunct
|
19
|
+
def initialize(var_names, aGoal)
|
20
|
+
@ctx = Core::Context.new
|
21
|
+
ctx.add_vars(var_names)
|
22
|
+
@goal = Rela::Fresh.compose_goals(aGoal)
|
18
23
|
end
|
19
24
|
|
25
|
+
# Run the query, that is, try to find ALL solutions
|
26
|
+
# of the provided qoal.
|
27
|
+
# One solution corresponds to allowed value associated
|
28
|
+
# to the provided logical variable(s).
|
29
|
+
#
|
20
30
|
def run
|
21
31
|
result = []
|
22
|
-
solver =
|
32
|
+
solver = goal.achieve(ctx) # A solver == Fiber(-like) yielding Context
|
23
33
|
# require 'debug'
|
34
|
+
|
24
35
|
loop do
|
25
|
-
|
26
|
-
|
27
|
-
outcome = solver.resume
|
28
|
-
break if outcome.nil?
|
36
|
+
outcome = solver.resume(ctx)
|
37
|
+
break if outcome.nil? # No other solution?
|
29
38
|
|
30
|
-
|
31
|
-
result << build_solution(outcome)
|
39
|
+
result << outcome.build_solution.values if outcome.success?
|
32
40
|
end
|
33
41
|
|
34
42
|
format_solutions(result)
|
@@ -36,13 +44,6 @@ module MiniKraken
|
|
36
44
|
|
37
45
|
private
|
38
46
|
|
39
|
-
# @return [Array] A vector of assignment for each variable
|
40
|
-
def build_solution(outcome)
|
41
|
-
env.vars.values.map do |var|
|
42
|
-
outcome.success? ? var.quote(outcome) : nil
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
47
|
# Transform the solutions into sequence of conscells.
|
47
48
|
# @param solutions [Array<Array>] An array of solution.
|
48
49
|
# A solution is in itself an array of bindings (one per variable)
|
@@ -55,14 +56,11 @@ module MiniKraken
|
|
55
56
|
# @param anArray [Array]
|
56
57
|
# @param simplify [Boolean]
|
57
58
|
def arr2list(anArray, simplify)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
new_tail = Core::ConsCell.new(elem, new_tail)
|
59
|
+
if anArray.size == 1 && simplify
|
60
|
+
anArray[0]
|
61
|
+
else
|
62
|
+
Composite::List.make_list(anArray)
|
63
63
|
end
|
64
|
-
|
65
|
-
new_tail
|
66
64
|
end
|
67
65
|
end # class
|
68
66
|
end # module
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../core/relation'
|
4
|
+
|
5
|
+
module MiniKraken
|
6
|
+
module Rela
|
7
|
+
# A binary relation between sets X and Y is a subset of the Cartesian product
|
8
|
+
# X × Y; that is, it is a set of ordered pairs (x, y) consisting of elements
|
9
|
+
# x in X and y in Y.
|
10
|
+
class BinaryRelation < Core::Relation
|
11
|
+
# @param aName [String] Name of the relation.
|
12
|
+
def initialize(aName)
|
13
|
+
super(aName, 2)
|
14
|
+
freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.symmetric
|
18
|
+
define_method :commute_cond do |arg1, arg2, ctx|
|
19
|
+
w1 = weight_arg(arg1, ctx)
|
20
|
+
w2 = weight_arg(arg2, ctx)
|
21
|
+
if w2 > w1
|
22
|
+
[arg2, arg1]
|
23
|
+
else
|
24
|
+
[arg1, arg2]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end # class
|
29
|
+
end # module
|
30
|
+
end # module
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require_relative '../core/context'
|
5
|
+
require_relative '../core/duck_fiber'
|
6
|
+
require_relative '../core/fail'
|
7
|
+
require_relative '../core/goal'
|
8
|
+
require_relative 'conj2'
|
9
|
+
|
10
|
+
require_relative 'goal_relation'
|
11
|
+
|
12
|
+
module MiniKraken
|
13
|
+
module Rela
|
14
|
+
# A polyadic relation (i.e. it can takes an arbitrary number of argumentt)
|
15
|
+
# that behaves as the disjunction of its arguments.
|
16
|
+
# It succeeds if at least one of its goal arguments succeeds.
|
17
|
+
class Conde < GoalRelation
|
18
|
+
include Singleton
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
super('conde', Core::Arity.new(1, '*'))
|
22
|
+
end
|
23
|
+
|
24
|
+
# A relation is polyadic when it accepts an arbitrary number of arguments.
|
25
|
+
# @return [TrueClass]
|
26
|
+
def polyadic?
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param actuals [Array<Term>] A two-elements array
|
31
|
+
# @param ctx [Core::Context] A vocabulary object
|
32
|
+
# @return [Fiber<Context>] A Fiber that yields Outcomes objects
|
33
|
+
def solver_for(actuals, ctx)
|
34
|
+
args = *validated_args(actuals)
|
35
|
+
Fiber.new { cond(args, ctx) }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Yields [Context, NilClass] result of the disjunction
|
39
|
+
# @param goals [Array<Goal>] Array of goals
|
40
|
+
# @param ctx [Context] A ctxabulary object
|
41
|
+
def cond(goals, ctx)
|
42
|
+
# require 'debug'
|
43
|
+
success = false
|
44
|
+
ctx.place_bt_point
|
45
|
+
|
46
|
+
goals.each do |g|
|
47
|
+
fiber = nil
|
48
|
+
|
49
|
+
case g
|
50
|
+
when Core::Goal
|
51
|
+
fiber = g.achieve(ctx)
|
52
|
+
when Array
|
53
|
+
conjunct = conjunction(g)
|
54
|
+
fiber = conjunct.achieve(ctx)
|
55
|
+
# when Core::ConsCell
|
56
|
+
# goal_array = to_goal_array(g)
|
57
|
+
# conjunct = conjunction(goal_array)
|
58
|
+
# fiber = conjunct.achieve(ctx)
|
59
|
+
else
|
60
|
+
raise NotImplementedError
|
61
|
+
end
|
62
|
+
|
63
|
+
loop do
|
64
|
+
outcome = fiber.resume(ctx)
|
65
|
+
break if outcome.nil?
|
66
|
+
|
67
|
+
if outcome.success?
|
68
|
+
success = true
|
69
|
+
Fiber.yield outcome
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
ctx.next_alternative
|
74
|
+
end
|
75
|
+
|
76
|
+
Fiber.yield ctx.failed! unless success
|
77
|
+
ctx.retract_bt_point
|
78
|
+
Fiber.yield nil
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def validated_args(actuals)
|
84
|
+
result = []
|
85
|
+
|
86
|
+
actuals.each do |arg|
|
87
|
+
case arg
|
88
|
+
when Core::Goal, Core::Context
|
89
|
+
result << arg
|
90
|
+
|
91
|
+
when Array
|
92
|
+
result << validated_args(arg)
|
93
|
+
|
94
|
+
else
|
95
|
+
prefix = "#{name} expects goal as argument, found a "
|
96
|
+
raise StandardError, prefix + "'#{arg.class}'"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
result
|
101
|
+
end
|
102
|
+
|
103
|
+
# Given an array of goals, build the conjunction of these.
|
104
|
+
def conjunction(goal_array)
|
105
|
+
result = nil
|
106
|
+
|
107
|
+
loop do
|
108
|
+
conjunctions = []
|
109
|
+
goal_array.each_slice(2) do |uno_duo|
|
110
|
+
if uno_duo.size == 2
|
111
|
+
conjunctions << Core::Goal.new(Rela::Conj2.instance, uno_duo)
|
112
|
+
else
|
113
|
+
conjunctions << uno_duo[0]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
if conjunctions.size == 1
|
117
|
+
result = conjunctions[0]
|
118
|
+
break
|
119
|
+
end
|
120
|
+
goal_array = conjunctions
|
121
|
+
end
|
122
|
+
|
123
|
+
result
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_goal_array(aCons)
|
127
|
+
array = []
|
128
|
+
curr_node = aCons
|
129
|
+
loop do
|
130
|
+
array << curr_node.car if curr_node.car.kind_of?(Core::Goal)
|
131
|
+
break unless curr_node.cdr
|
132
|
+
break unless curr_node.car.kind_of?(Core::Goal)
|
133
|
+
|
134
|
+
curr_node = curr_node.cdr
|
135
|
+
end
|
136
|
+
|
137
|
+
array
|
138
|
+
end
|
139
|
+
end # class
|
140
|
+
|
141
|
+
Conde.instance.freeze
|
142
|
+
end # module
|
143
|
+
end # module
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
require_relative '../core/context'
|
6
|
+
require_relative '../core/duck_fiber'
|
7
|
+
require_relative 'goal_relation'
|
8
|
+
|
9
|
+
module MiniKraken
|
10
|
+
module Rela
|
11
|
+
# The conjunction is a relation that accepts only two goals as its
|
12
|
+
# arguments. It succeeds if and only if both its goal arguments succeeds.
|
13
|
+
class Conj2 < GoalRelation
|
14
|
+
include Singleton
|
15
|
+
|
16
|
+
# Default initialization
|
17
|
+
def initialize
|
18
|
+
super('conj2', 2)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param actuals [Array<Core::Term>] A two-elements array
|
22
|
+
# @param ctx [Core::Context] A context object
|
23
|
+
# @return [Fiber<Core::Context>] A Fiber that yields Context objects
|
24
|
+
def solver_for(actuals, ctx)
|
25
|
+
g1, g2 = *validated_args(actuals)
|
26
|
+
Fiber.new { conjunction(g1, g2, ctx) }
|
27
|
+
end
|
28
|
+
|
29
|
+
# Yields [Core::Context, NilClass] result of the conjunction
|
30
|
+
# @param g1 [Goal] First goal argument
|
31
|
+
# @param g2 [Goal] Second goal argument
|
32
|
+
# @param ctx [Core::Context] A ctxabulary object
|
33
|
+
def conjunction(g1, g2, ctx)
|
34
|
+
# require 'debug'
|
35
|
+
if g1.relation.kind_of?(Core::Fail) || g2.relation.kind_of?(Core::Fail)
|
36
|
+
Fiber.yield ctx.failed!
|
37
|
+
else
|
38
|
+
outcome1 = outcome2 = nil
|
39
|
+
fiber1 = g1.achieve(ctx)
|
40
|
+
|
41
|
+
loop do
|
42
|
+
outcome1 = fiber1.resume(ctx)
|
43
|
+
break if outcome1.nil?
|
44
|
+
|
45
|
+
if outcome1.success?
|
46
|
+
fiber2 = g2.achieve(ctx)
|
47
|
+
loop do
|
48
|
+
outcome2 = fiber2.resume(ctx)
|
49
|
+
break if outcome2.nil?
|
50
|
+
|
51
|
+
Fiber.yield outcome2
|
52
|
+
end
|
53
|
+
else
|
54
|
+
Fiber.yield outcome1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Fiber.yield nil
|
60
|
+
end
|
61
|
+
end # class
|
62
|
+
|
63
|
+
Conj2.instance.freeze
|
64
|
+
end # module
|
65
|
+
end # module
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require_relative '../core/relation'
|
5
|
+
require_relative '../core/entry'
|
6
|
+
|
7
|
+
module MiniKraken
|
8
|
+
module Rela
|
9
|
+
# A user-defined relation with:
|
10
|
+
# - a user-defined name,
|
11
|
+
# - a ordered list of generic formal arguments, and;
|
12
|
+
# - a goal template expression.
|
13
|
+
class DefRelation < Core::Relation
|
14
|
+
include Core::Entry # Add behaviour of symbol table entries
|
15
|
+
|
16
|
+
# @return [Array<FormalArg>] formal arguments of this DefRelation
|
17
|
+
attr_reader :formals
|
18
|
+
|
19
|
+
# @return [Term] Expression to be fulfilled and parametrized with formals
|
20
|
+
attr_reader :expression
|
21
|
+
|
22
|
+
# @param aName [String] name of def relation
|
23
|
+
# @param anExpression [Term]
|
24
|
+
# @param theFormals [Array<String>]
|
25
|
+
def initialize(aName, anExpression, theFormals)
|
26
|
+
@formals = validated_formals(theFormals)
|
27
|
+
formal_vars = formals.map { |nm| Core::LogVarRef.new(nm) }
|
28
|
+
raw_expression = validated_expression(anExpression)
|
29
|
+
@expression = replace_expression(raw_expression, theFormals, formal_vars)
|
30
|
+
super(aName, formals.size)
|
31
|
+
freeze
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param actuals [Array<Term>] A two-elements array
|
35
|
+
# @param ctx [Context] A Context object
|
36
|
+
# @return [Fiber<Outcome>] A Fiber(-like) instance that yields Outcomes
|
37
|
+
def solver_for(actuals, ctx)
|
38
|
+
actual_expr = replace_expression(expression, formals, actuals)
|
39
|
+
actual_expr.achieve(ctx)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def validated_formals(theFormals)
|
45
|
+
# Make the formal names unique, to avoid name collision
|
46
|
+
theFormals.map { |name| "#{name}_#{SecureRandom.uuid}" }
|
47
|
+
end
|
48
|
+
|
49
|
+
def validated_expression(aGoalTemplate)
|
50
|
+
raise StandardError unless aGoalTemplate
|
51
|
+
|
52
|
+
compose_goals(aGoalTemplate)
|
53
|
+
end
|
54
|
+
|
55
|
+
def compose_goals(subgoals)
|
56
|
+
nested_goal = nil
|
57
|
+
|
58
|
+
case subgoals
|
59
|
+
when Core::Goal
|
60
|
+
nested_goal = subgoals
|
61
|
+
|
62
|
+
when Array
|
63
|
+
goal_array = subgoals
|
64
|
+
loop do
|
65
|
+
conjunctions = []
|
66
|
+
goal_array.each_slice(2) do |uno_duo|
|
67
|
+
if uno_duo.size == 2
|
68
|
+
conjunctions << Core::Goal.new(Conj2.instance, uno_duo)
|
69
|
+
else
|
70
|
+
conjunctions << uno_duo[0]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
if conjunctions.size == 1
|
74
|
+
nested_goal = conjunctions[0]
|
75
|
+
break
|
76
|
+
end
|
77
|
+
goal_array = conjunctions
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
nested_goal
|
82
|
+
end
|
83
|
+
|
84
|
+
# With the given expression, create a new expression where
|
85
|
+
# each allusion to original variable is replaced by the
|
86
|
+
# by its corresponding actual value.
|
87
|
+
def replace_expression(anExpression, original, actual)
|
88
|
+
raw_pairs = original.zip(actual) # [original, actual]
|
89
|
+
anExpression.dup_cond(raw_pairs.to_h)
|
90
|
+
end
|
91
|
+
end # class
|
92
|
+
end # module
|
93
|
+
end # module
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
require_relative '../core/context'
|
6
|
+
require_relative '../core/duck_fiber'
|
7
|
+
require_relative 'goal_relation'
|
8
|
+
|
9
|
+
module MiniKraken
|
10
|
+
module Rela
|
11
|
+
# The disjunction is a relation that accepts only goal(s) as its two
|
12
|
+
# arguments. It succeeds if at least one of its goal arguments succeeds.
|
13
|
+
class Disj2 < GoalRelation
|
14
|
+
include Singleton
|
15
|
+
|
16
|
+
# Default initialization
|
17
|
+
def initialize
|
18
|
+
super('disj2', 2)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param actuals [Array<Core::Term>] A two-elements array
|
22
|
+
# @param ctx [Core::Context] A context object
|
23
|
+
# @return [Fiber<Core::Context>] A Fiber that yields Context objects
|
24
|
+
def solver_for(actuals, ctx)
|
25
|
+
g1, g2 = *validated_args(actuals)
|
26
|
+
Fiber.new { disjunction(g1, g2, ctx) }
|
27
|
+
end
|
28
|
+
|
29
|
+
# Yields [Core::Context, NilClass] result of the disjunction
|
30
|
+
# @param g1 [Goal] First goal argument
|
31
|
+
# @param g2 [Goal] Second goal argument
|
32
|
+
# @param ctx [Core::Context] A ctxabulary object
|
33
|
+
def disjunction(g1, g2, ctx)
|
34
|
+
# require 'debug'
|
35
|
+
if g1.relation.kind_of?(Core::Fail) && g2.relation.kind_of?(Core::Fail)
|
36
|
+
Fiber.yield ctx.failed!
|
37
|
+
else
|
38
|
+
ctx.place_bt_point
|
39
|
+
outcome1 = nil
|
40
|
+
outcome2 = nil
|
41
|
+
f1 = g1.achieve(ctx)
|
42
|
+
loop do
|
43
|
+
outcome1 = f1.resume(ctx)
|
44
|
+
break if outcome1.nil?
|
45
|
+
|
46
|
+
if outcome1.success?
|
47
|
+
Fiber.yield outcome1
|
48
|
+
ctx.next_alternative
|
49
|
+
end
|
50
|
+
end
|
51
|
+
f2 = g2.achieve(ctx)
|
52
|
+
loop do
|
53
|
+
outcome2 = f2.resume(ctx)
|
54
|
+
break if outcome2.nil?
|
55
|
+
|
56
|
+
if outcome2.success?
|
57
|
+
Fiber.yield outcome2
|
58
|
+
ctx.next_alternative
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
ctx.retract_bt_point
|
64
|
+
Fiber.yield nil
|
65
|
+
end
|
66
|
+
end # class
|
67
|
+
|
68
|
+
Disj2.instance.freeze
|
69
|
+
end # module
|
70
|
+
end # module
|