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.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/README.md +16 -16
  4. data/lib/mini_kraken/atomic/all_atomic.rb +1 -0
  5. data/lib/mini_kraken/atomic/atomic_term.rb +32 -17
  6. data/lib/mini_kraken/atomic/k_integer.rb +0 -4
  7. data/lib/mini_kraken/atomic/k_string.rb +17 -0
  8. data/lib/mini_kraken/atomic/k_symbol.rb +0 -6
  9. data/lib/mini_kraken/composite/all_composite.rb +4 -0
  10. data/lib/mini_kraken/composite/composite_term.rb +2 -18
  11. data/lib/mini_kraken/composite/cons_cell.rb +178 -11
  12. data/lib/mini_kraken/composite/cons_cell_visitor.rb +12 -64
  13. data/lib/mini_kraken/composite/list.rb +32 -0
  14. data/lib/mini_kraken/core/all_core.rb +8 -0
  15. data/lib/mini_kraken/core/any_value.rb +31 -7
  16. data/lib/mini_kraken/core/arity.rb +69 -0
  17. data/lib/mini_kraken/core/association.rb +29 -4
  18. data/lib/mini_kraken/core/association_copy.rb +50 -0
  19. data/lib/mini_kraken/core/base_term.rb +13 -0
  20. data/lib/mini_kraken/core/blackboard.rb +315 -0
  21. data/lib/mini_kraken/core/bookmark.rb +46 -0
  22. data/lib/mini_kraken/core/context.rb +624 -0
  23. data/lib/mini_kraken/core/duck_fiber.rb +21 -19
  24. data/lib/mini_kraken/core/entry.rb +40 -0
  25. data/lib/mini_kraken/core/fail.rb +20 -18
  26. data/lib/mini_kraken/core/fusion.rb +29 -0
  27. data/lib/mini_kraken/core/goal.rb +20 -29
  28. data/lib/mini_kraken/core/log_var.rb +4 -30
  29. data/lib/mini_kraken/core/log_var_ref.rb +72 -48
  30. data/lib/mini_kraken/core/nullary_relation.rb +2 -9
  31. data/lib/mini_kraken/core/parametrized_term.rb +61 -0
  32. data/lib/mini_kraken/core/relation.rb +14 -28
  33. data/lib/mini_kraken/core/scope.rb +67 -0
  34. data/lib/mini_kraken/core/solver_adapter.rb +58 -0
  35. data/lib/mini_kraken/core/specification.rb +48 -0
  36. data/lib/mini_kraken/core/succeed.rb +21 -17
  37. data/lib/mini_kraken/core/symbol_table.rb +137 -0
  38. data/lib/mini_kraken/core/term.rb +15 -4
  39. data/lib/mini_kraken/glue/dsl.rb +35 -69
  40. data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
  41. data/lib/mini_kraken/rela/all_rela.rb +8 -0
  42. data/lib/mini_kraken/rela/binary_relation.rb +30 -0
  43. data/lib/mini_kraken/rela/conde.rb +146 -0
  44. data/lib/mini_kraken/rela/conj2.rb +65 -0
  45. data/lib/mini_kraken/rela/def_relation.rb +64 -0
  46. data/lib/mini_kraken/rela/disj2.rb +70 -0
  47. data/lib/mini_kraken/rela/fresh.rb +98 -0
  48. data/lib/mini_kraken/{core → rela}/goal_relation.rb +6 -8
  49. data/lib/mini_kraken/rela/unify.rb +258 -0
  50. data/lib/mini_kraken/version.rb +1 -1
  51. data/spec/atomic/atomic_term_spec.rb +23 -20
  52. data/spec/atomic/k_symbol_spec.rb +0 -5
  53. data/spec/composite/cons_cell_spec.rb +116 -0
  54. data/spec/composite/cons_cell_visitor_spec.rb +16 -3
  55. data/spec/composite/list_spec.rb +50 -0
  56. data/spec/core/any_value_spec.rb +52 -0
  57. data/spec/core/arity_spec.rb +91 -0
  58. data/spec/core/association_copy_spec.rb +69 -0
  59. data/spec/core/association_spec.rb +25 -0
  60. data/spec/core/blackboard_spec.rb +287 -0
  61. data/spec/core/bookmark_spec.rb +40 -0
  62. data/spec/core/context_spec.rb +221 -0
  63. data/spec/core/core_spec.rb +40 -0
  64. data/spec/core/duck_fiber_spec.rb +22 -46
  65. data/spec/core/fail_spec.rb +5 -6
  66. data/spec/core/goal_spec.rb +20 -11
  67. data/spec/core/log_var_ref_spec.rb +80 -5
  68. data/spec/core/log_var_spec.rb +35 -6
  69. data/spec/core/nullary_relation_spec.rb +33 -0
  70. data/spec/core/parametrized_tem_spec.rb +39 -0
  71. data/spec/core/relation_spec.rb +33 -0
  72. data/spec/core/scope_spec.rb +73 -0
  73. data/spec/core/solver_adapter_spec.rb +70 -0
  74. data/spec/core/specification_spec.rb +43 -0
  75. data/spec/core/succeed_spec.rb +5 -5
  76. data/spec/core/symbol_table_spec.rb +142 -0
  77. data/spec/glue/dsl_chap1_spec.rb +88 -99
  78. data/spec/glue/dsl_chap2_spec.rb +59 -41
  79. data/spec/glue/run_star_expression_spec.rb +69 -896
  80. data/spec/{core → rela}/conde_spec.rb +50 -46
  81. data/spec/rela/conj2_spec.rb +123 -0
  82. data/spec/rela/def_relation_spec.rb +119 -0
  83. data/spec/rela/disj2_spec.rb +117 -0
  84. data/spec/rela/fresh_spec.rb +147 -0
  85. data/spec/rela/unify_spec.rb +369 -0
  86. data/spec/support/factory_atomic.rb +7 -0
  87. data/spec/support/factory_composite.rb +21 -0
  88. metadata +71 -48
  89. data/lib/mini_kraken/core/association_walker.rb +0 -183
  90. data/lib/mini_kraken/core/base_arg.rb +0 -10
  91. data/lib/mini_kraken/core/binary_relation.rb +0 -63
  92. data/lib/mini_kraken/core/composite_goal.rb +0 -46
  93. data/lib/mini_kraken/core/conde.rb +0 -143
  94. data/lib/mini_kraken/core/conj2.rb +0 -79
  95. data/lib/mini_kraken/core/def_relation.rb +0 -53
  96. data/lib/mini_kraken/core/designation.rb +0 -55
  97. data/lib/mini_kraken/core/disj2.rb +0 -72
  98. data/lib/mini_kraken/core/environment.rb +0 -73
  99. data/lib/mini_kraken/core/equals.rb +0 -191
  100. data/lib/mini_kraken/core/formal_arg.rb +0 -22
  101. data/lib/mini_kraken/core/formal_ref.rb +0 -25
  102. data/lib/mini_kraken/core/freshness.rb +0 -45
  103. data/lib/mini_kraken/core/goal_arg.rb +0 -12
  104. data/lib/mini_kraken/core/goal_template.rb +0 -102
  105. data/lib/mini_kraken/core/outcome.rb +0 -63
  106. data/lib/mini_kraken/core/tap.rb +0 -46
  107. data/lib/mini_kraken/core/vocabulary.rb +0 -446
  108. data/lib/mini_kraken/glue/fresh_env.rb +0 -108
  109. data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
  110. data/spec/core/association_walker_spec.rb +0 -194
  111. data/spec/core/conj2_spec.rb +0 -116
  112. data/spec/core/def_relation_spec.rb +0 -99
  113. data/spec/core/disj2_spec.rb +0 -100
  114. data/spec/core/environment_spec.rb +0 -144
  115. data/spec/core/equals_spec.rb +0 -319
  116. data/spec/core/goal_template_spec.rb +0 -74
  117. data/spec/core/outcome_spec.rb +0 -56
  118. data/spec/core/vocabulary_spec.rb +0 -220
  119. data/spec/glue/fresh_env_factory_spec.rb +0 -99
  120. data/spec/glue/fresh_env_spec.rb +0 -62
@@ -1,12 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'goal_arg'
3
+ require_relative 'base_term'
4
4
 
5
5
  module MiniKraken
6
6
  module Core
7
- # The generalization of any data value that can be
8
- # passed as arugement to a goal.
9
- class Term < GoalArg
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
@@ -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 '../core/def_relation'
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(Core::Conde.instance, args)
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(Core::Conj2.instance, [convert(arg1), convert(arg2)])
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 defrel(relationName, theFormals, &aGoalTemplateExpr)
68
- start_defrel
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
- @defrel_formals << theFormals
59
+ formals = [theFormals]
73
60
  when Array
74
- @defrel_formals.merge(theFormals)
61
+ formals = theFormals
75
62
  end
63
+ rela = Rela::DefRelation.new(relationName, aGoalExpr, formals)
64
+ add_defrel(rela)
76
65
 
77
- formals = @defrel_formals.map { |name| Core::FormalArg.new(name) }
78
- g_template = aGoalTemplateExpr.call
79
- result = Core::DefRelation.new(relationName, g_template, formals)
80
- add_defrel(result)
66
+ # start_defrel
81
67
 
82
- end_defrel
83
- result
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(Core::Disj2.instance, [convert(arg1), convert(arg2)])
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 equals(arg1, arg2)
96
- # require 'debug'
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
- def fresh(var_names, goal)
101
- vars = nil
102
- if @dsl_mode == :defrel
103
- if var_names.kind_of?(String)
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
- head = nil
124
- members.reverse_each { |elem| head = Composite::ConsCell.new(convert(elem), head) }
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.new(nil, nil)
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 = {} unless instance_variable_defined?(:@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 = {} unless instance_variable_defined?(:@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/any_value'
4
- require_relative '../composite/cons_cell'
5
- require_relative 'fresh_env'
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 [FreshEnv] The environment in which run* variables will reside.
11
- attr_reader :env
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 goal [Core::Goal, Array<Core::Goal>] A single goal or an array of goals to conjunct
15
- def initialize(var_names, goal)
16
- vnames = var_names.kind_of?(String) ? [var_names] : var_names
17
- @env = FreshEnv.new(vnames, goal)
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 = env.goal.attain(env)
32
+ solver = goal.achieve(ctx) # A solver == Fiber(-like) yielding Context
23
33
  # require 'debug'
34
+
24
35
  loop do
25
- env.clear
26
- env.clear_rankings
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
- env.propagate(outcome) if result.empty? && outcome.success?
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
- return anArray[0] if anArray.size == 1 && simplify
59
-
60
- new_tail = nil
61
- anArray.reverse_each do |elem|
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,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'conj2'
4
+ require_relative 'disj2'
5
+ require_relative 'fresh'
6
+ require_relative 'unify'
7
+ require_relative 'conde'
8
+ require_relative 'def_relation'
@@ -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