Class: RubyProlog::Core

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby-prolog/ruby-prolog.rb

Instance Method Summary collapse

Constructor Details

#initializeCore

Returns a new instance of Core.



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/ruby-prolog/ruby-prolog.rb', line 340

def initialize
  # We do not need to predefine predicates like this because they will automatically be defined for us.
  # write = Predicate.new "write"
  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] }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args) ⇒ Object



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/ruby-prolog/ruby-prolog.rb', line 302

def method_missing(meth, *args)
    # puts "NEW PRED #{meth} #{meth.class}"
    pred = Predicate.new(meth)
    # proc = Proc.new {pred}


    # We only want to define the method on this specific object instance to avoid polluting global namespaces.
    
    # You can't do this..
    # class << self
    #           module_eval do
    #             send(:define_method, m, proc)
    #           end
    #         end
    
    # Nor this..
    # define_method(meth) {pred}

    # Nor this..
    # self.send(:define_method, meth, proc)
    
    # And you don't want to pollute the global namespace like this...
    # Object.class_eval{ define_method(meth){pr} }
    
    
    # Sooooo... I know this doesn't really make intuitive sense,
    # but you need to get the eigenclass and then define
    # the method within that context in such a way that we
    # have access to local variables, like this...
    class << self; self; end.module_eval do
      define_method meth, Proc.new{pred}
    end
    # ...which is major fuglytown, but I don't know how to do it any other way.

    return pred
end

Instance Method Details

#_resolve_body(body, env, cut) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/ruby-prolog/ruby-prolog.rb', line 214

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]
      require 'pp'
      # pp 'G ' + goal.class.to_s
      # pp goal.pred
      for d_head, d_body in goal.pred.defs
      # for d_head, d_body in goal.defs
        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) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/ruby-prolog/ruby-prolog.rb', line 158

def _unify(x, x_env, y, y_env, trail, tmp_env)

  loop {
    if 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 == y.pred
    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) ⇒ Object



266
267
268
269
270
271
# File 'lib/ruby-prolog/ruby-prolog.rb', line 266

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

#is(*syms, &block) ⇒ Object



291
292
293
294
295
296
297
298
299
300
# File 'lib/ruby-prolog/ruby-prolog.rb', line 291

def is(*syms,&block)
  $is_cnt ||= 0
  is = Predicate.new "IS_#{$is_cnt += 1}"
  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) ⇒ Object



199
200
201
202
203
# File 'lib/ruby-prolog/ruby-prolog.rb', line 199

def list(*x)
  y = nil
  x.reverse_each {|e| y = Cons.new(e, y)}
  return y
end

#query(*goals) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/ruby-prolog/ruby-prolog.rb', line 274

def query(*goals)
  count = 0
  results = Array.new
  # printout = proc {|x|
  #   x = x[0] if x.length == 1
  #   printf "%d %s\n", count, x.inspect
  # }
  resolve(*goals) {|env|
    count += 1
    results << env[goals]
    # printout[env[goals]]
  }
  # printout[goals] if count == 0
  return results
end

#resolve(*goals) ⇒ Object



206
207
208
209
210
211
# File 'lib/ruby-prolog/ruby-prolog.rb', line 206

def resolve(*goals)
  env = Environment.new
  _resolve_body(list(*goals), env, [false]) {
    yield env
  }
end

#trace(flag) ⇒ Object



261
262
263
# File 'lib/ruby-prolog/ruby-prolog.rb', line 261

def trace(flag)
  $_trace = flag
end