mini_kraken 0.1.12 → 0.2.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 +334 -0
 - data/CHANGELOG.md +54 -0
 - data/README.md +95 -13
 - data/lib/mini_kraken.rb +7 -1
 - data/lib/mini_kraken/core/any_value.rb +5 -1
 - data/lib/mini_kraken/core/atomic_term.rb +1 -0
 - data/lib/mini_kraken/core/conde.rb +1 -1
 - data/lib/mini_kraken/core/conj2.rb +3 -3
 - data/lib/mini_kraken/core/cons_cell.rb +29 -1
 - data/lib/mini_kraken/core/cons_cell_visitor.rb +102 -0
 - data/lib/mini_kraken/core/def_relation.rb +4 -0
 - data/lib/mini_kraken/core/disj2.rb +2 -2
 - data/lib/mini_kraken/core/environment.rb +2 -2
 - data/lib/mini_kraken/core/equals.rb +60 -26
 - data/lib/mini_kraken/core/formal_ref.rb +2 -1
 - data/lib/mini_kraken/core/goal.rb +4 -2
 - data/lib/mini_kraken/core/goal_template.rb +44 -2
 - data/lib/mini_kraken/core/k_boolean.rb +4 -0
 - data/lib/mini_kraken/core/k_symbol.rb +11 -0
 - data/lib/mini_kraken/core/outcome.rb +11 -1
 - data/lib/mini_kraken/core/variable.rb +10 -4
 - data/lib/mini_kraken/core/variable_ref.rb +7 -0
 - data/lib/mini_kraken/core/vocabulary.rb +8 -3
 - data/lib/mini_kraken/glue/dsl.rb +236 -0
 - data/lib/mini_kraken/glue/fresh_env.rb +31 -3
 - data/lib/mini_kraken/glue/fresh_env_factory.rb +83 -0
 - data/lib/mini_kraken/glue/run_star_expression.rb +3 -5
 - data/lib/mini_kraken/version.rb +1 -1
 - data/mini_kraken.gemspec +6 -3
 - data/spec/.rubocop.yml +13 -0
 - data/spec/core/conde_spec.rb +10 -10
 - data/spec/core/conj2_spec.rb +7 -7
 - data/spec/core/cons_cell_spec.rb +35 -0
 - data/spec/core/cons_cell_visitor_spec.rb +144 -0
 - data/spec/core/def_relation_spec.rb +6 -5
 - data/spec/core/disj2_spec.rb +5 -5
 - data/spec/core/duck_fiber_spec.rb +2 -2
 - data/spec/core/equals_spec.rb +34 -21
 - data/spec/core/goal_spec.rb +2 -2
 - data/spec/core/k_boolean_spec.rb +6 -0
 - data/spec/core/k_symbol_spec.rb +4 -0
 - data/spec/core/outcome_spec.rb +8 -0
 - data/spec/core/variable_ref_spec.rb +3 -0
 - data/spec/glue/dsl_chap1_spec.rb +679 -0
 - data/spec/glue/dsl_chap2_spec.rb +100 -0
 - data/spec/glue/fresh_env_factory_spec.rb +97 -0
 - data/spec/glue/run_star_expression_spec.rb +11 -11
 - metadata +17 -4
 
| 
         @@ -11,6 +11,17 @@ module MiniKraken 
     | 
|
| 
       11 
11 
     | 
    
         
             
                  def initialize(aValue)
         
     | 
| 
       12 
12 
     | 
    
         
             
                    super(aValue)
         
     | 
| 
       13 
13 
     | 
    
         
             
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # Returns the name or string corresponding to value.
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # @return [String]
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def id2name
         
     | 
| 
      
 18 
     | 
    
         
            +
                    value.id2name
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  # Returns a string representing the MiniKraken symbol.
         
     | 
| 
      
 22 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 23 
     | 
    
         
            +
                    ":#{id2name}"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
       14 
25 
     | 
    
         
             
                end # class
         
     | 
| 
       15 
26 
     | 
    
         
             
              end # module
         
     | 
| 
       16 
27 
     | 
    
         
             
            end # module
         
     | 
| 
         @@ -24,7 +24,11 @@ unless MiniKraken::Core.constants(false).include? :Outcome 
     | 
|
| 
       24 
24 
     | 
    
         
             
                      new(:"#s", aParent)
         
     | 
| 
       25 
25 
     | 
    
         
             
                    end
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                    def  
     | 
| 
      
 27 
     | 
    
         
            +
                    def failure?
         
     | 
| 
      
 28 
     | 
    
         
            +
                      resultant != :"#s"
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    def success?
         
     | 
| 
       28 
32 
     | 
    
         
             
                      resultant == :"#s"
         
     | 
| 
       29 
33 
     | 
    
         
             
                    end
         
     | 
| 
       30 
34 
     | 
    
         | 
| 
         @@ -39,6 +43,12 @@ unless MiniKraken::Core.constants(false).include? :Outcome 
     | 
|
| 
       39 
43 
     | 
    
         
             
                      are_equal
         
     | 
| 
       40 
44 
     | 
    
         
             
                    end
         
     | 
| 
       41 
45 
     | 
    
         | 
| 
      
 46 
     | 
    
         
            +
                    # Remove associations of variables of this environment, if
         
     | 
| 
      
 47 
     | 
    
         
            +
                    # persistence flag is set to false.
         
     | 
| 
      
 48 
     | 
    
         
            +
                    def prune!
         
     | 
| 
      
 49 
     | 
    
         
            +
                      parent.prune(self)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
       42 
52 
     | 
    
         
             
                    protected
         
     | 
| 
       43 
53 
     | 
    
         | 
| 
       44 
54 
     | 
    
         
             
                    def introspect
         
     | 
| 
         @@ -24,11 +24,17 @@ module MiniKraken 
     | 
|
| 
       24 
24 
     | 
    
         
             
                    name != i_name
         
     | 
| 
       25 
25 
     | 
    
         
             
                  end
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                  def quote( 
     | 
| 
       28 
     | 
    
         
            -
                    raise StandardError, "class #{ 
     | 
| 
      
 27 
     | 
    
         
            +
                  def quote(env)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    raise StandardError, "class #{env}" unless env.kind_of?(Vocabulary)
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
                    val =  
     | 
| 
       31 
     | 
    
         
            -
                     
     | 
| 
      
 30 
     | 
    
         
            +
                    val = env.quote_ref(self)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    unless val
         
     | 
| 
      
 32 
     | 
    
         
            +
                      result = AnyValue.new(name, env, env.names_fused(name))
         
     | 
| 
      
 33 
     | 
    
         
            +
                    else
         
     | 
| 
      
 34 
     | 
    
         
            +
                      result = val
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    result
         
     | 
| 
       32 
38 
     | 
    
         
             
                  end
         
     | 
| 
       33 
39 
     | 
    
         
             
                end # class
         
     | 
| 
       34 
40 
     | 
    
         
             
              end # module
         
     | 
| 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require_relative 'term'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'designation'
         
     | 
| 
       4 
5 
     | 
    
         
             
            require_relative 'any_value'
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
7 
     | 
    
         
             
            module MiniKraken
         
     | 
| 
         @@ -13,7 +14,13 @@ module MiniKraken 
     | 
|
| 
       13 
14 
     | 
    
         | 
| 
       14 
15 
     | 
    
         
             
                  # @param aName [String] The name of the variable
         
     | 
| 
       15 
16 
     | 
    
         
             
                  def initialize(aName)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    super()
         
     | 
| 
       16 
18 
     | 
    
         
             
                    init_designation(aName)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    name.freeze
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 23 
     | 
    
         
            +
                    name
         
     | 
| 
       17 
24 
     | 
    
         
             
                  end
         
     | 
| 
       18 
25 
     | 
    
         | 
| 
       19 
26 
     | 
    
         
             
                  # @param aValue [Term]
         
     | 
| 
         @@ -171,7 +171,7 @@ module MiniKraken 
     | 
|
| 
       171 
171 
     | 
    
         
             
                    to_fuse.map { |i_name| i_name2var(i_name) }
         
     | 
| 
       172 
172 
     | 
    
         
             
                  end
         
     | 
| 
       173 
173 
     | 
    
         | 
| 
       174 
     | 
    
         
            -
                  # Fuse the given variables 
     | 
| 
      
 174 
     | 
    
         
            +
                  # Fuse the given variables:
         
     | 
| 
       175 
175 
     | 
    
         
             
                  # Collect all their associations
         
     | 
| 
       176 
176 
     | 
    
         
             
                  # Put them under a new internal name
         
     | 
| 
       177 
177 
     | 
    
         
             
                  # Remove all entries from old internal names
         
     | 
| 
         @@ -331,8 +331,9 @@ module MiniKraken 
     | 
|
| 
       331 
331 
     | 
    
         
             
                  #   variable name.
         
     | 
| 
       332 
332 
     | 
    
         
             
                  # @param aName [String] User-defined variable name
         
     | 
| 
       333 
333 
     | 
    
         
             
                  def names_fused(aName)
         
     | 
| 
      
 334 
     | 
    
         
            +
                    # require 'debug'
         
     | 
| 
       334 
335 
     | 
    
         
             
                    var = name2var(aName)
         
     | 
| 
       335 
     | 
    
         
            -
                    return [] unless var 
     | 
| 
      
 336 
     | 
    
         
            +
                    return [] unless var&.fused?
         
     | 
| 
       336 
337 
     | 
    
         | 
| 
       337 
338 
     | 
    
         
             
                    i_name = var.i_name
         
     | 
| 
       338 
339 
     | 
    
         
             
                    names = []
         
     | 
| 
         @@ -394,12 +395,16 @@ module MiniKraken 
     | 
|
| 
       394 
395 
     | 
    
         
             
                    name2var(aVarName) ? true : false
         
     | 
| 
       395 
396 
     | 
    
         
             
                  end
         
     | 
| 
       396 
397 
     | 
    
         | 
| 
      
 398 
     | 
    
         
            +
                  def prune(anOutcome)
         
     | 
| 
      
 399 
     | 
    
         
            +
                    anOutcome # Don't touch outcome
         
     | 
| 
      
 400 
     | 
    
         
            +
                  end
         
     | 
| 
      
 401 
     | 
    
         
            +
             
     | 
| 
       397 
402 
     | 
    
         
             
                  def inspect
         
     | 
| 
       398 
403 
     | 
    
         
             
                    result = +"#<#{self.class.name}:#{object_id.to_s(16)} @parent="
         
     | 
| 
       399 
404 
     | 
    
         
             
                    if parent
         
     | 
| 
       400 
405 
     | 
    
         
             
                      result << "#<#{parent.class.name}:#{parent.object_id.to_s(16)}>"
         
     | 
| 
       401 
406 
     | 
    
         
             
                    else
         
     | 
| 
       402 
     | 
    
         
            -
                      result << nil
         
     | 
| 
      
 407 
     | 
    
         
            +
                      result << 'nil'
         
     | 
| 
       403 
408 
     | 
    
         
             
                    end
         
     | 
| 
       404 
409 
     | 
    
         
             
                    result << introspect
         
     | 
| 
       405 
410 
     | 
    
         
             
                    result << '>'
         
     | 
| 
         @@ -0,0 +1,236 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'set'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative '../core/any_value'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative '../core/conde'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative '../core/conj2'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative '../core/cons_cell'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative '../core/def_relation'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_relative '../core/disj2'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require_relative '../core/equals'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require_relative '../core/fail'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require_relative '../core/formal_arg'
         
     | 
| 
      
 13 
     | 
    
         
            +
            require_relative '../core/formal_ref'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require_relative '../glue/fresh_env'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require_relative '../glue/fresh_env_factory'
         
     | 
| 
      
 16 
     | 
    
         
            +
            require_relative '../core/goal_template'
         
     | 
| 
      
 17 
     | 
    
         
            +
            require_relative '../core/k_boolean'
         
     | 
| 
      
 18 
     | 
    
         
            +
            require_relative '../core/k_symbol'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require_relative '../core/succeed'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require_relative '../core/variable_ref'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require_relative 'fresh_env'
         
     | 
| 
      
 22 
     | 
    
         
            +
            require_relative 'run_star_expression'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            module MiniKraken
         
     | 
| 
      
 26 
     | 
    
         
            +
              module Glue
         
     | 
| 
      
 27 
     | 
    
         
            +
                # The mixin module that implements the methods for the DSL
         
     | 
| 
      
 28 
     | 
    
         
            +
                # (DSL = Domain Specific Langague) that allows MiniKraken
         
     | 
| 
      
 29 
     | 
    
         
            +
                # users to embed Minikanren in their Ruby code.
         
     | 
| 
      
 30 
     | 
    
         
            +
                module DSL
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # A run* expression tries to find all the solutions
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # that meet the given goal.
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # @return [Core::ConsCell] A list of solutions
         
     | 
| 
      
 34 
     | 
    
         
            +
                  def run_star(var_names, goal)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    program = RunStarExpression.new(var_names, goal)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    program.run
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def conde(*goals)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    # require 'debug'
         
     | 
| 
      
 41 
     | 
    
         
            +
                    args = goals.map do |goal_maybe|
         
     | 
| 
      
 42 
     | 
    
         
            +
                      if goal_maybe.kind_of?(Array)
         
     | 
| 
      
 43 
     | 
    
         
            +
                        goal_maybe.map { |g| convert(g) }
         
     | 
| 
      
 44 
     | 
    
         
            +
                      else
         
     | 
| 
      
 45 
     | 
    
         
            +
                        convert(goal_maybe)
         
     | 
| 
      
 46 
     | 
    
         
            +
                      end
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    Core::Goal.new(Core::Conde.instance, args)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  # conj2 stands for conjunction of two arguments.
         
     | 
| 
      
 53 
     | 
    
         
            +
                  # Returns a goal linked to the Core::Conj2 relation.
         
     | 
| 
      
 54 
     | 
    
         
            +
                  # The rule of that relation succeeds when both arguments succeed.
         
     | 
| 
      
 55 
     | 
    
         
            +
                  # @param arg1 [Core::Goal]
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # @param arg2 [Core::Goal]
         
     | 
| 
      
 57 
     | 
    
         
            +
                  # @return [Core::Failure|Core::Success]
         
     | 
| 
      
 58 
     | 
    
         
            +
                  def conj2(arg1, arg2)
         
     | 
| 
      
 59 
     | 
    
         
            +
                   goal_class.new(Core::Conj2.instance, [convert(arg1), convert(arg2)])
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  def cons(car_item, cdr_item = nil)
         
     | 
| 
      
 63 
     | 
    
         
            +
                    tail = cdr_item.nil? ? cdr_item : convert(cdr_item)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    Core::ConsCell.new(convert(car_item), tail)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  def defrel(relationName, theFormals, &aGoalTemplateExpr)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    start_defrel
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                    case theFormals
         
     | 
| 
      
 71 
     | 
    
         
            +
                      when String
         
     | 
| 
      
 72 
     | 
    
         
            +
                        @defrel_formals << theFormals
         
     | 
| 
      
 73 
     | 
    
         
            +
                      when Array
         
     | 
| 
      
 74 
     | 
    
         
            +
                        @defrel_formals.merge(theFormals)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 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)
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                    end_defrel
         
     | 
| 
      
 83 
     | 
    
         
            +
                    result
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  def disj2(arg1, arg2)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    goal_class.new(Core::Disj2.instance, [convert(arg1), convert(arg2)])
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  # @return [Core::Fail] A goal that unconditionally fails.
         
     | 
| 
      
 91 
     | 
    
         
            +
                  def _fail
         
     | 
| 
      
 92 
     | 
    
         
            +
                    goal_class.new(Core::Fail.instance, [])
         
     | 
| 
      
 93 
     | 
    
         
            +
                  end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                  def equals(arg1, arg2)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    # require 'debug'
         
     | 
| 
      
 97 
     | 
    
         
            +
                    goal_class.new(Core::Equals.instance, [convert(arg1), convert(arg2)])
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 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::VariableRef)
         
     | 
| 
      
 111 
     | 
    
         
            +
                        vars = [var_names]
         
     | 
| 
      
 112 
     | 
    
         
            +
                      else
         
     | 
| 
      
 113 
     | 
    
         
            +
                        vars = var_names
         
     | 
| 
      
 114 
     | 
    
         
            +
                      end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                      FreshEnv.new(vars, goal)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    end
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                  def list(*members)
         
     | 
| 
      
 121 
     | 
    
         
            +
                    return null if members.empty?
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                    head = nil
         
     | 
| 
      
 124 
     | 
    
         
            +
                    members.reverse_each { |elem| head = Core::ConsCell.new(convert(elem), head) }
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                    head
         
     | 
| 
      
 127 
     | 
    
         
            +
                  end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  # @return [ConsCell] Returns an empty list, that is, a pair whose members are nil.
         
     | 
| 
      
 130 
     | 
    
         
            +
                  def null
         
     | 
| 
      
 131 
     | 
    
         
            +
                    Core::ConsCell.new(nil, nil)
         
     | 
| 
      
 132 
     | 
    
         
            +
                  end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                  # @return [Core::Succeed] A goal that unconditionally succeeds.
         
     | 
| 
      
 135 
     | 
    
         
            +
                  def succeed
         
     | 
| 
      
 136 
     | 
    
         
            +
                    goal_class.new(Core::Succeed.instance, [])
         
     | 
| 
      
 137 
     | 
    
         
            +
                  end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                  private
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                  def convert(anArgument)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    converted = nil
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                    case anArgument
         
     | 
| 
      
 145 
     | 
    
         
            +
                      when Symbol
         
     | 
| 
      
 146 
     | 
    
         
            +
                        if anArgument.id2name =~ /_\d+/
         
     | 
| 
      
 147 
     | 
    
         
            +
                          rank = anArgument.id2name.slice(1..-1).to_i
         
     | 
| 
      
 148 
     | 
    
         
            +
                          any_val = Core::AnyValue.allocate
         
     | 
| 
      
 149 
     | 
    
         
            +
                          any_val.instance_variable_set(:@rank, rank)
         
     | 
| 
      
 150 
     | 
    
         
            +
                          converted = any_val
         
     | 
| 
      
 151 
     | 
    
         
            +
                        elsif anArgument.id2name =~ /^"#[ft]"$/
         
     | 
| 
      
 152 
     | 
    
         
            +
                          converted = Core::KBoolean.new(anArgument)
         
     | 
| 
      
 153 
     | 
    
         
            +
                        else
         
     | 
| 
      
 154 
     | 
    
         
            +
                          converted = Core::KSymbol.new(anArgument)
         
     | 
| 
      
 155 
     | 
    
         
            +
                        end
         
     | 
| 
      
 156 
     | 
    
         
            +
                      when String
         
     | 
| 
      
 157 
     | 
    
         
            +
                        if anArgument =~ /^#[ft]$/
         
     | 
| 
      
 158 
     | 
    
         
            +
                          converted = Core::KBoolean.new(anArgument)
         
     | 
| 
      
 159 
     | 
    
         
            +
                        else
         
     | 
| 
      
 160 
     | 
    
         
            +
                          msg = "Internal error: undefined conversion for #{anArgument.class}"
         
     | 
| 
      
 161 
     | 
    
         
            +
                          raise StandardError, msg
         
     | 
| 
      
 162 
     | 
    
         
            +
                        end
         
     | 
| 
      
 163 
     | 
    
         
            +
                      when false, true
         
     | 
| 
      
 164 
     | 
    
         
            +
                        converted = Core::KBoolean.new(anArgument)
         
     | 
| 
      
 165 
     | 
    
         
            +
                      when Core::KBoolean
         
     | 
| 
      
 166 
     | 
    
         
            +
                        converted = anArgument
         
     | 
| 
      
 167 
     | 
    
         
            +
                      when Core::FormalRef
         
     | 
| 
      
 168 
     | 
    
         
            +
                        converted = anArgument
         
     | 
| 
      
 169 
     | 
    
         
            +
                      when FreshEnv
         
     | 
| 
      
 170 
     | 
    
         
            +
                        converted = anArgument
         
     | 
| 
      
 171 
     | 
    
         
            +
                      when Core::Goal
         
     | 
| 
      
 172 
     | 
    
         
            +
                        converted = anArgument
         
     | 
| 
      
 173 
     | 
    
         
            +
                      when Core::GoalTemplate
         
     | 
| 
      
 174 
     | 
    
         
            +
                        converted = anArgument
         
     | 
| 
      
 175 
     | 
    
         
            +
                      when Core::VariableRef
         
     | 
| 
      
 176 
     | 
    
         
            +
                        converted = anArgument
         
     | 
| 
      
 177 
     | 
    
         
            +
                      when Core::ConsCell
         
     | 
| 
      
 178 
     | 
    
         
            +
                        converted = anArgument
         
     | 
| 
      
 179 
     | 
    
         
            +
                      else
         
     | 
| 
      
 180 
     | 
    
         
            +
                        msg = "Internal error: undefined conversion for #{anArgument.class}"
         
     | 
| 
      
 181 
     | 
    
         
            +
                        raise StandardError, msg
         
     | 
| 
      
 182 
     | 
    
         
            +
                    end
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
                    converted
         
     | 
| 
      
 185 
     | 
    
         
            +
                  end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                  def default_mode
         
     | 
| 
      
 188 
     | 
    
         
            +
                    @dsl_mode = :default
         
     | 
| 
      
 189 
     | 
    
         
            +
                    @defrel_formals = nil
         
     | 
| 
      
 190 
     | 
    
         
            +
                  end
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                  def goal_class
         
     | 
| 
      
 193 
     | 
    
         
            +
                    default_mode unless instance_variable_defined?(:@dsl_mode)
         
     | 
| 
      
 194 
     | 
    
         
            +
                    @dsl_mode == :default ? Core::Goal : Core::GoalTemplate
         
     | 
| 
      
 195 
     | 
    
         
            +
                  end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                  def start_defrel
         
     | 
| 
      
 198 
     | 
    
         
            +
                    @dsl_mode = :defrel
         
     | 
| 
      
 199 
     | 
    
         
            +
                    @defrel_formals = Set.new
         
     | 
| 
      
 200 
     | 
    
         
            +
                  end
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                  def end_defrel
         
     | 
| 
      
 203 
     | 
    
         
            +
                    default_mode
         
     | 
| 
      
 204 
     | 
    
         
            +
                  end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                  def add_defrel(aDefRelation)
         
     | 
| 
      
 207 
     | 
    
         
            +
                    @defrels = {} unless instance_variable_defined?(:@defrels)
         
     | 
| 
      
 208 
     | 
    
         
            +
                    @defrels[aDefRelation.name] = aDefRelation
         
     | 
| 
      
 209 
     | 
    
         
            +
                  end
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                  def method_missing(mth, *args)
         
     | 
| 
      
 212 
     | 
    
         
            +
                    result = nil
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 215 
     | 
    
         
            +
                      result = super(mth, *args)
         
     | 
| 
      
 216 
     | 
    
         
            +
                    rescue NameError
         
     | 
| 
      
 217 
     | 
    
         
            +
                      name = mth.id2name
         
     | 
| 
      
 218 
     | 
    
         
            +
                      @defrels = {} unless instance_variable_defined?(:@defrels)
         
     | 
| 
      
 219 
     | 
    
         
            +
                      if @defrels.include?(name)
         
     | 
| 
      
 220 
     | 
    
         
            +
                        def_relation = @defrels[name]
         
     | 
| 
      
 221 
     | 
    
         
            +
                        result = Core::Goal.new(def_relation, args.map { |el| convert(el) })
         
     | 
| 
      
 222 
     | 
    
         
            +
                      else
         
     | 
| 
      
 223 
     | 
    
         
            +
                        default_mode unless instance_variable_defined?(:@dsl_mode)
         
     | 
| 
      
 224 
     | 
    
         
            +
                        if @dsl_mode == :defrel && @defrel_formals.include?(name)
         
     | 
| 
      
 225 
     | 
    
         
            +
                          result = Core::FormalRef.new(name)
         
     | 
| 
      
 226 
     | 
    
         
            +
                        else
         
     | 
| 
      
 227 
     | 
    
         
            +
                          result = Core::VariableRef.new(name)
         
     | 
| 
      
 228 
     | 
    
         
            +
                        end
         
     | 
| 
      
 229 
     | 
    
         
            +
                      end
         
     | 
| 
      
 230 
     | 
    
         
            +
                    end
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
                    result
         
     | 
| 
      
 233 
     | 
    
         
            +
                  end
         
     | 
| 
      
 234 
     | 
    
         
            +
                end # module
         
     | 
| 
      
 235 
     | 
    
         
            +
              end # module
         
     | 
| 
      
 236 
     | 
    
         
            +
            end # module
         
     | 
| 
         @@ -2,13 +2,14 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require_relative '../core/environment'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require_relative '../core/conj2'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative '../core/goal_template'
         
     | 
| 
       5 
6 
     | 
    
         
             
            require_relative '../core/variable'
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            module MiniKraken
         
     | 
| 
       8 
9 
     | 
    
         
             
              module Glue
         
     | 
| 
       9 
10 
     | 
    
         
             
                # A combination of an Environment (= a scope for one or more variables)
         
     | 
| 
       10 
11 
     | 
    
         
             
                # and a goal. It quacks like a Goal object: when receiving the attain message,
         
     | 
| 
       11 
     | 
    
         
            -
                # it  
     | 
| 
      
 12 
     | 
    
         
            +
                # it attempts to achieve its given goal.
         
     | 
| 
       12 
13 
     | 
    
         
             
                # (fresh (x) (== 'pea q))
         
     | 
| 
       13 
14 
     | 
    
         
             
                # Introduces the new variable 'x'
         
     | 
| 
       14 
15 
     | 
    
         
             
                # Takes a list of names and a goal-like object
         
     | 
| 
         @@ -17,22 +18,45 @@ module MiniKraken 
     | 
|
| 
       17 
18 
     | 
    
         
             
                  # @return [Goal]
         
     | 
| 
       18 
19 
     | 
    
         
             
                  attr_reader :goal
         
     | 
| 
       19 
20 
     | 
    
         | 
| 
      
 21 
     | 
    
         
            +
                  # @return [TrueClass, FalseClass] Do associations persist after goal exec?
         
     | 
| 
      
 22 
     | 
    
         
            +
                  attr_reader :persistent
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
       20 
24 
     | 
    
         
             
                  # @param theNames [Array<String>] The variable names
         
     | 
| 
       21 
25 
     | 
    
         
             
                  # @param aGoal [Goal, Array<Goal>] The goal to achieve or the conjunction of them.
         
     | 
| 
       22 
     | 
    
         
            -
                  def initialize(theNames, aGoal)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  def initialize(theNames, aGoal, persistence = true)
         
     | 
| 
       23 
27 
     | 
    
         
             
                    super()
         
     | 
| 
       24 
28 
     | 
    
         
             
                    @goal = valid_goal(aGoal)
         
     | 
| 
       25 
     | 
    
         
            -
                    theNames.each  
     | 
| 
      
 29 
     | 
    
         
            +
                    theNames.each do |nm|
         
     | 
| 
      
 30 
     | 
    
         
            +
                      var = Core::Variable.new(nm)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      add_var(var)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @persistent = persistence
         
     | 
| 
       26 
34 
     | 
    
         
             
                  end
         
     | 
| 
       27 
35 
     | 
    
         | 
| 
       28 
36 
     | 
    
         
             
                  # Attempt to achieve the goal given this environment
         
     | 
| 
       29 
37 
     | 
    
         
             
                  # @param aParent [Environment]
         
     | 
| 
       30 
38 
     | 
    
         
             
                  # @return [Fiber<Outcome>] A Fiber object that will generate the results.
         
     | 
| 
       31 
39 
     | 
    
         
             
                  def attain(aParent)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    # require 'debug'
         
     | 
| 
       32 
41 
     | 
    
         
             
                    self.parent = aParent
         
     | 
| 
       33 
42 
     | 
    
         
             
                    goal.attain(self)
         
     | 
| 
       34 
43 
     | 
    
         
             
                  end
         
     | 
| 
       35 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
                  # Remove associations of variables of this environment, if
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # persistence flag is set to false.
         
     | 
| 
      
 47 
     | 
    
         
            +
                  def prune(anOutcome)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    return super(anOutcome) if persistent
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    vars.each_value do |v|
         
     | 
| 
      
 51 
     | 
    
         
            +
                      v_name = v.name
         
     | 
| 
      
 52 
     | 
    
         
            +
                      if anOutcome.associations.include?(v_name)
         
     | 
| 
      
 53 
     | 
    
         
            +
                        anOutcome.associations.delete(v_name)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      end
         
     | 
| 
      
 55 
     | 
    
         
            +
                    end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    anOutcome
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
       36 
60 
     | 
    
         
             
                  protected
         
     | 
| 
       37 
61 
     | 
    
         | 
| 
       38 
62 
     | 
    
         
             
                  def introspect
         
     | 
| 
         @@ -49,6 +73,8 @@ module MiniKraken 
     | 
|
| 
       49 
73 
     | 
    
         
             
                        result = aGoal
         
     | 
| 
       50 
74 
     | 
    
         
             
                      when FreshEnv
         
     | 
| 
       51 
75 
     | 
    
         
             
                        result = aGoal
         
     | 
| 
      
 76 
     | 
    
         
            +
                      when Core::GoalTemplate
         
     | 
| 
      
 77 
     | 
    
         
            +
                        result = aGoal
         
     | 
| 
       52 
78 
     | 
    
         
             
                      when Array # an Array of Goal?..
         
     | 
| 
       53 
79 
     | 
    
         
             
                        goal_array = aGoal
         
     | 
| 
       54 
80 
     | 
    
         
             
                        loop do
         
     | 
| 
         @@ -66,6 +92,8 @@ module MiniKraken 
     | 
|
| 
       66 
92 
     | 
    
         
             
                          end
         
     | 
| 
       67 
93 
     | 
    
         
             
                          goal_array = conjunctions
         
     | 
| 
       68 
94 
     | 
    
         
             
                        end
         
     | 
| 
      
 95 
     | 
    
         
            +
                      else
         
     | 
| 
      
 96 
     | 
    
         
            +
                        raise StandardError, "Cannot handle argumment type #{aGoal.class}"
         
     | 
| 
       69 
97 
     | 
    
         
             
                    end
         
     | 
| 
       70 
98 
     | 
    
         | 
| 
       71 
99 
     | 
    
         
             
                    result
         
     |