class RubyProlog::Core

Public Class Methods

new() click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 470
def initialize
  @db = Database.new
  # These predicates are made available in all environments
  write[:X].calls{|env| print env[:X]; true}
  writenl[:X].calls{|env| puts env[:X]; true}
  nl[:X].calls{|e| puts; true}
  eq[:X,:Y].calls{|env| env.unify(env[:X], env[:Y])}
  noteq[:X,:Y].calls{|env| env[:X] != env[:Y]}
  atomic[:X].calls do |env|
    case env[:X]
    when Symbol, Predicate, Goal; false
    else true
    end
  end
  notatomic[:X].calls do |env|
    case env[:X]
    when Symbol, Predicate, Goal; true
    else false
    end
  end
  numeric[:X].calls{|env| Numeric === env[:X] }

  not_[:X].calls do |env|
    found_solution = false
    resolve(env[:X], :CUT) { found_solution = true }
    found_solution == false
  end

  # Enable here so the predicates above don't make it in to_prolog output
  @db.enable_listing
end

Public Instance Methods

_resolve_body(body, env, cut) { || ... } click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 377
def _resolve_body(body, env, cut)
  if body.nil?
    yield
  else
    goal, rest = body
    if goal == :CUT
      _resolve_body(rest, env, cut) {
        yield
      }
      cut[0] = true
    else
      d_env = Environment.new
      d_cut = [false]
      for d_head, d_body in @db.by_id[goal.pred_id].clauses
        break if d_cut[0] or cut[0]
        trail = []
        if _unify_(goal, env, d_head, d_env, trail, d_env)
          if Proc === d_body
            if d_body[CallbackEnvironment.new(d_env, trail, self)]
              _resolve_body(rest, env, cut) {
                yield
              }
            end
          else
            _resolve_body(d_body, d_env, d_cut) {
              _resolve_body(rest, env, cut) {
                yield
              }
              d_cut[0] ||= cut[0]
            }
          end
        end
        for x, x_env in trail
          x_env.delete(x)
        end
        d_env.clear
      end
    end
  end
end
_unify(x, x_env, y, y_env, trail, tmp_env) click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 319
def _unify(x, x_env, y, y_env, trail, tmp_env)

  loop {
    if x == :_
      return true
    elsif Symbol === x
      xp = x_env.get(x)
      if xp.nil?
        y, y_env = y_env.dereference(y)
        unless x == y and x_env == y_env
          x_env.put(x, [y, y_env])
          trail << [x, x_env] unless x_env == tmp_env
        end
        return true
      else
        x, x_env = xp
        x, x_env = x_env.dereference(x)
      end
    elsif Symbol === y
      x, x_env, y, y_env = y, y_env, x, x_env
    else
      break
    end
  }

  if Goal === x and Goal === y
    return false unless x.pred_id == y.pred_id
    x, y = x.args, y.args
  end

  if Array === x and Array === y
    return false unless x.length == y.length
    for i in 0 ... x.length     # x.each_index do |i| も可
      return false unless _unify(x[i], x_env, y[i], y_env, trail, tmp_env)
    end
    return true
  else
    return x == y
  end

end
_unify_(x, x_env, y, y_env, trail, tmp_env) click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 425
def _unify_(x, x_env, y, y_env, trail, tmp_env)
  lhs, rhs = x_env[x].inspect, y.inspect if $_trace
  unified = _unify(x, x_env, y, y_env, trail, tmp_env)
  printf("\t%s %s %s\n", lhs, (unified ? "~" : "!~"), rhs) if $_trace
  return unified
end
initialize_copy(orig) click to toggle source
Calls superclass method
# File lib/ruby-prolog/ruby-prolog.rb, line 502
def initialize_copy(orig)
  super
  @db = @db.clone
end
is(*syms,&block) click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 445
def is(*syms,&block)
  $is_cnt ||= 0
  is = @db.register("IS_#{$is_cnt += 1}", skip_listing: true)
  raise "At least one symbol needed" unless syms.size > 0
  is[*syms].calls do |env|
    value = block.call(*syms[1..-1].map{|x| env[x]})
    env.unify(syms.first, value)
  end
  is[*syms]
end
list(*x) click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 362
def list(*x)
  y = nil
  x.reverse_each {|e| y = Cons.new(e, y)}
  return y
end
method_missing(meth, *args) click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 456
def method_missing(meth, *args)
  pred = @db.register(meth)

  # We only want to define the method on this specific object instance to avoid polluting global namespaces.
  define_singleton_method(meth){ @db.by_name[meth] }

  pred
end
query(&block) click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 433
def query(&block)
  goals = instance_eval(&block)
  goals = [goals] unless goals.is_a?(Array)
  results = []

  resolve(*goals.map(&:to_goal)) {|env|
    results << env.solution
  }
  return results
end
resolve(*goals) { |env| ... } click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 369
def resolve(*goals)
  env = Environment.new
  _resolve_body(list(*goals), env, [false]) {
    yield env
  }
end
to_prolog() click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 465
def to_prolog
  @db.listing.map(&:to_prolog).join("\n\n")
end
trace(flag) click to toggle source
# File lib/ruby-prolog/ruby-prolog.rb, line 420
def trace(flag)
  $_trace = flag
end