mini_kraken 0.2.04 → 0.3.00
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +16 -16
- data/lib/mini_kraken/atomic/all_atomic.rb +1 -0
- data/lib/mini_kraken/atomic/atomic_term.rb +32 -17
- data/lib/mini_kraken/atomic/k_integer.rb +0 -4
- data/lib/mini_kraken/atomic/k_string.rb +17 -0
- data/lib/mini_kraken/atomic/k_symbol.rb +0 -6
- data/lib/mini_kraken/composite/all_composite.rb +4 -0
- data/lib/mini_kraken/composite/composite_term.rb +2 -18
- data/lib/mini_kraken/composite/cons_cell.rb +178 -11
- data/lib/mini_kraken/composite/cons_cell_visitor.rb +12 -64
- 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 +624 -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 +4 -30
- data/lib/mini_kraken/core/log_var_ref.rb +72 -48
- data/lib/mini_kraken/core/nullary_relation.rb +2 -9
- data/lib/mini_kraken/core/parametrized_term.rb +61 -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 +35 -69
- 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 +146 -0
- data/lib/mini_kraken/rela/conj2.rb +65 -0
- data/lib/mini_kraken/rela/def_relation.rb +64 -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 +6 -8
- data/lib/mini_kraken/rela/unify.rb +258 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/spec/atomic/atomic_term_spec.rb +23 -20
- data/spec/atomic/k_symbol_spec.rb +0 -5
- data/spec/composite/cons_cell_spec.rb +116 -0
- data/spec/composite/cons_cell_visitor_spec.rb +16 -3
- data/spec/composite/list_spec.rb +50 -0
- data/spec/core/any_value_spec.rb +52 -0
- data/spec/core/arity_spec.rb +91 -0
- data/spec/core/association_copy_spec.rb +69 -0
- data/spec/core/association_spec.rb +25 -0
- data/spec/core/blackboard_spec.rb +287 -0
- data/spec/core/bookmark_spec.rb +40 -0
- data/spec/core/context_spec.rb +221 -0
- data/spec/core/core_spec.rb +40 -0
- data/spec/core/duck_fiber_spec.rb +22 -46
- data/spec/core/fail_spec.rb +5 -6
- data/spec/core/goal_spec.rb +20 -11
- data/spec/core/log_var_ref_spec.rb +80 -5
- data/spec/core/log_var_spec.rb +35 -6
- 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 -99
- data/spec/glue/dsl_chap2_spec.rb +59 -41
- data/spec/glue/run_star_expression_spec.rb +69 -896
- data/spec/{core → rela}/conde_spec.rb +50 -46
- 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 +7 -0
- data/spec/support/factory_composite.rb +21 -0
- metadata +71 -48
- data/lib/mini_kraken/core/association_walker.rb +0 -183
- 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/conde.rb +0 -143
- data/lib/mini_kraken/core/conj2.rb +0 -79
- 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 -191
- 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/outcome.rb +0 -63
- data/lib/mini_kraken/core/tap.rb +0 -46
- data/lib/mini_kraken/core/vocabulary.rb +0 -446
- data/lib/mini_kraken/glue/fresh_env.rb +0 -108
- data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
- data/spec/core/association_walker_spec.rb +0 -194
- data/spec/core/conj2_spec.rb +0 -116
- data/spec/core/def_relation_spec.rb +0 -99
- data/spec/core/disj2_spec.rb +0 -100
- data/spec/core/environment_spec.rb +0 -144
- data/spec/core/equals_spec.rb +0 -319
- data/spec/core/goal_template_spec.rb +0 -74
- data/spec/core/outcome_spec.rb +0 -56
- data/spec/core/vocabulary_spec.rb +0 -220
- data/spec/glue/fresh_env_factory_spec.rb +0 -99
- data/spec/glue/fresh_env_spec.rb +0 -62
@@ -1,12 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'base_term'
|
4
4
|
|
5
5
|
module MiniKraken
|
6
6
|
module Core
|
7
|
-
# The generalization of any
|
8
|
-
# passed as
|
9
|
-
|
7
|
+
# The generalization of any object that can be:
|
8
|
+
# - passed as argument to a goal.
|
9
|
+
# - passed as argument to a MiniKraken procedure
|
10
|
+
# - contained in a compositer term,
|
11
|
+
# - associated with a logical variable.
|
12
|
+
class Term < BaseTerm
|
13
|
+
# Abstract method.
|
14
|
+
# Make a copy of self with all the variable reference being
|
15
|
+
# replaced by the corresponding value in the Hash.
|
16
|
+
# @param _substitutions [Hash {String => Term}]
|
17
|
+
# @return [Term]
|
18
|
+
def dup_cond(_substitutions)
|
19
|
+
raise NotImplementedError, "Not implementation for #{self.class}."
|
20
|
+
end
|
10
21
|
end # class
|
11
22
|
end # module
|
12
23
|
end # module
|
data/lib/mini_kraken/glue/dsl.rb
CHANGED
@@ -1,27 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'set'
|
4
|
+
|
5
|
+
require_relative '../core/all_core'
|
4
6
|
require_relative '../atomic/all_atomic'
|
5
|
-
require_relative '../core/any_value'
|
6
|
-
require_relative '../core/conde'
|
7
|
-
require_relative '../core/conj2'
|
8
7
|
require_relative '../composite/cons_cell'
|
9
|
-
require_relative '../
|
10
|
-
require_relative '../core/disj2'
|
11
|
-
require_relative '../core/equals'
|
12
|
-
require_relative '../core/fail'
|
13
|
-
require_relative '../core/formal_arg'
|
14
|
-
require_relative '../core/formal_ref'
|
15
|
-
require_relative '../glue/fresh_env'
|
16
|
-
require_relative '../glue/fresh_env_factory'
|
17
|
-
require_relative '../core/goal_template'
|
18
|
-
require_relative '../core/succeed'
|
19
|
-
require_relative '../core/tap'
|
20
|
-
require_relative '../core/log_var_ref'
|
21
|
-
require_relative 'fresh_env'
|
8
|
+
require_relative '../rela/all_rela'
|
22
9
|
require_relative 'run_star_expression'
|
23
10
|
|
24
|
-
|
25
11
|
module MiniKraken
|
26
12
|
module Glue
|
27
13
|
# The mixin module that implements the methods for the DSL
|
@@ -37,7 +23,6 @@ module MiniKraken
|
|
37
23
|
end
|
38
24
|
|
39
25
|
def conde(*goals)
|
40
|
-
# require 'debug'
|
41
26
|
args = goals.map do |goal_maybe|
|
42
27
|
if goal_maybe.kind_of?(Array)
|
43
28
|
goal_maybe.map { |g| convert(g) }
|
@@ -46,7 +31,7 @@ module MiniKraken
|
|
46
31
|
end
|
47
32
|
end
|
48
33
|
|
49
|
-
Core::Goal.new(
|
34
|
+
Core::Goal.new(Rela::Conde.instance, args)
|
50
35
|
end
|
51
36
|
|
52
37
|
# conj2 stands for conjunction of two arguments.
|
@@ -56,7 +41,7 @@ module MiniKraken
|
|
56
41
|
# @param arg2 [Core::Goal]
|
57
42
|
# @return [Core::Failure|Core::Success]
|
58
43
|
def conj2(arg1, arg2)
|
59
|
-
goal_class.new(
|
44
|
+
goal_class.new(Rela::Conj2.instance, [convert(arg1), convert(arg2)])
|
60
45
|
end
|
61
46
|
|
62
47
|
def cons(car_item, cdr_item = nil)
|
@@ -64,27 +49,33 @@ module MiniKraken
|
|
64
49
|
Composite::ConsCell.new(convert(car_item), tail)
|
65
50
|
end
|
66
51
|
|
67
|
-
def
|
68
|
-
|
52
|
+
def null_list
|
53
|
+
Composite::ConsCell.new(nil, nil)
|
54
|
+
end
|
69
55
|
|
56
|
+
def defrel(relationName, theFormals, aGoalExpr)
|
70
57
|
case theFormals
|
71
58
|
when String
|
72
|
-
|
59
|
+
formals = [theFormals]
|
73
60
|
when Array
|
74
|
-
|
61
|
+
formals = theFormals
|
75
62
|
end
|
63
|
+
rela = Rela::DefRelation.new(relationName, aGoalExpr, formals)
|
64
|
+
add_defrel(rela)
|
76
65
|
|
77
|
-
|
78
|
-
g_template = aGoalTemplateExpr.call
|
79
|
-
result = Core::DefRelation.new(relationName, g_template, formals)
|
80
|
-
add_defrel(result)
|
66
|
+
# start_defrel
|
81
67
|
|
82
|
-
|
83
|
-
|
68
|
+
# formals = @defrel_formals.map { |name| Core::FormalArg.new(name) }
|
69
|
+
# g_template = aGoalTemplateExpr.call
|
70
|
+
# result = Core::DefRelation.new(relationName, g_template, formals)
|
71
|
+
# add_defrel(result)
|
72
|
+
|
73
|
+
# end_defrel
|
74
|
+
# result
|
84
75
|
end
|
85
76
|
|
86
77
|
def disj2(arg1, arg2)
|
87
|
-
goal_class.new(
|
78
|
+
goal_class.new(Rela::Disj2.instance, [convert(arg1), convert(arg2)])
|
88
79
|
end
|
89
80
|
|
90
81
|
# @return [Core::Fail] A goal that unconditionally fails.
|
@@ -92,43 +83,26 @@ module MiniKraken
|
|
92
83
|
goal_class.new(Core::Fail.instance, [])
|
93
84
|
end
|
94
85
|
|
95
|
-
def
|
96
|
-
|
97
|
-
goal_class.new(Core::Equals.instance, [convert(arg1), convert(arg2)])
|
86
|
+
def unify(arg1, arg2)
|
87
|
+
goal_class.new(Rela::Unify.instance, [convert(arg1), convert(arg2)])
|
98
88
|
end
|
99
89
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
vars = [var_names]
|
105
|
-
else
|
106
|
-
vars = var_names
|
107
|
-
end
|
108
|
-
FreshEnvFactory.new(vars, goal)
|
109
|
-
else
|
110
|
-
if var_names.kind_of?(String) || var_names.kind_of?(Core::LogVarRef)
|
111
|
-
vars = [var_names]
|
112
|
-
else
|
113
|
-
vars = var_names
|
114
|
-
end
|
115
|
-
|
116
|
-
FreshEnv.new(vars, goal)
|
117
|
-
end
|
90
|
+
# @return [Core::Goal]
|
91
|
+
def fresh(names, subgoal)
|
92
|
+
# puts "#{__callee__} #{names}"
|
93
|
+
Rela::Fresh.build_goal(names, subgoal)
|
118
94
|
end
|
119
95
|
|
120
96
|
def list(*members)
|
121
97
|
return null if members.empty?
|
122
98
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
head
|
99
|
+
converted = members.map { |e| convert(e) }
|
100
|
+
Composite::List.make_list(converted)
|
127
101
|
end
|
128
102
|
|
129
103
|
# @return [ConsCell] Returns an empty list, that is, a pair whose members are nil.
|
130
104
|
def null
|
131
|
-
Composite::ConsCell.
|
105
|
+
Composite::ConsCell.null
|
132
106
|
end
|
133
107
|
|
134
108
|
# @return [Core::Succeed] A goal that unconditionally succeeds.
|
@@ -136,10 +110,6 @@ module MiniKraken
|
|
136
110
|
goal_class.new(Core::Succeed.instance, [])
|
137
111
|
end
|
138
112
|
|
139
|
-
def tap(arg1)
|
140
|
-
goal_class.new(Core::Tap.instance, [convert(arg1)])
|
141
|
-
end
|
142
|
-
|
143
113
|
private
|
144
114
|
|
145
115
|
def convert(anArgument)
|
@@ -168,18 +138,14 @@ module MiniKraken
|
|
168
138
|
converted = Atomic::KBoolean.new(anArgument)
|
169
139
|
when Atomic::KBoolean, Atomic::KSymbol
|
170
140
|
converted = anArgument
|
171
|
-
when Core::FormalRef
|
172
|
-
converted = anArgument
|
173
|
-
when FreshEnv
|
174
|
-
converted = anArgument
|
175
141
|
when Core::Goal
|
176
142
|
converted = anArgument
|
177
|
-
when Core::GoalTemplate
|
178
|
-
converted = anArgument
|
179
143
|
when Core::LogVarRef
|
180
144
|
converted = anArgument
|
181
145
|
when Composite::ConsCell
|
182
146
|
converted = anArgument
|
147
|
+
when NilClass
|
148
|
+
converted = anArgument
|
183
149
|
else
|
184
150
|
msg = "Internal error: undefined conversion for #{anArgument.class}"
|
185
151
|
raise StandardError, msg
|
@@ -208,7 +174,7 @@ module MiniKraken
|
|
208
174
|
end
|
209
175
|
|
210
176
|
def add_defrel(aDefRelation)
|
211
|
-
@defrels
|
177
|
+
@defrels ||= {}
|
212
178
|
@defrels[aDefRelation.name] = aDefRelation
|
213
179
|
end
|
214
180
|
|
@@ -219,7 +185,7 @@ module MiniKraken
|
|
219
185
|
result = super(mth, *args)
|
220
186
|
rescue NameError
|
221
187
|
name = mth.id2name
|
222
|
-
@defrels
|
188
|
+
@defrels ||= {}
|
223
189
|
if @defrels.include?(name)
|
224
190
|
def_relation = @defrels[name]
|
225
191
|
result = Core::Goal.new(def_relation, args.map { |el| convert(el) })
|
@@ -1,34 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../core/
|
4
|
-
require_relative '../composite/
|
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 = Composite::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,146 @@
|
|
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
|
89
|
+
result << arg
|
90
|
+
|
91
|
+
when Core::Context
|
92
|
+
result << arg
|
93
|
+
|
94
|
+
when Array
|
95
|
+
result << validated_args(arg)
|
96
|
+
|
97
|
+
else
|
98
|
+
prefix = "#{name} expects goal as argument, found a "
|
99
|
+
raise StandardError, prefix + "'#{arg.class}'"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
result
|
104
|
+
end
|
105
|
+
|
106
|
+
# Given an array of goals, build the conjunction of these.
|
107
|
+
def conjunction(goal_array)
|
108
|
+
result = nil
|
109
|
+
|
110
|
+
loop do
|
111
|
+
conjunctions = []
|
112
|
+
goal_array.each_slice(2) do |uno_duo|
|
113
|
+
if uno_duo.size == 2
|
114
|
+
conjunctions << Core::Goal.new(Rela::Conj2.instance, uno_duo)
|
115
|
+
else
|
116
|
+
conjunctions << uno_duo[0]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
if conjunctions.size == 1
|
120
|
+
result = conjunctions[0]
|
121
|
+
break
|
122
|
+
end
|
123
|
+
goal_array = conjunctions
|
124
|
+
end
|
125
|
+
|
126
|
+
result
|
127
|
+
end
|
128
|
+
|
129
|
+
def to_goal_array(aCons)
|
130
|
+
array = []
|
131
|
+
curr_node = aCons
|
132
|
+
loop do
|
133
|
+
array << curr_node.car if curr_node.car.kind_of?(Core::Goal)
|
134
|
+
break unless curr_node.cdr
|
135
|
+
break unless curr_node.car.kind_of?(Core::Goal)
|
136
|
+
|
137
|
+
curr_node = curr_node.cdr
|
138
|
+
end
|
139
|
+
|
140
|
+
array
|
141
|
+
end
|
142
|
+
end # class
|
143
|
+
|
144
|
+
Conde.instance.freeze
|
145
|
+
end # module
|
146
|
+
end # module
|