lib/micro_kanren/lisp.rb in micro_kanren-0.0.1 vs lib/micro_kanren/lisp.rb in micro_kanren-0.0.2

- old
+ new

@@ -2,44 +2,92 @@ module Lisp # Returns a Cons cell that is also marked as such for later identification. def cons(x, y) -> (m) { m.call(x, y) }.tap do |func| - func.instance_eval{ def cons_cell? ; true ; end } + func.instance_eval{ def ccel? ; true ; end } end end def car(z) ; z.call(-> (p, q) { p }) ; end def cdr(z) ; z.call(-> (p, q) { q }) ; end - def cons_cell?(d) - d.respond_to?(:cons_cell?) && d.cons_cell? + def cons?(d) + d.respond_to?(:ccel?) && d.ccel? end + alias :pair? :cons? + def map(func, list) + cons(func.call(car(list)), map(func, cdr(list))) if list + end + + def length(list) + list.nil? ? 0 : 1 + length(cdr(list)) + end + + # We implement scheme cons cells as Procs. This function returns a boolean + # identically to the Scheme procedure? function to avoid false positives. + def procedure?(elt) + elt.is_a?(Proc) && !cons?(elt) + end + # Search association list by predicate function. # Based on lua implementation by silentbicycle: # https://github.com/silentbicycle/lua-ukanren/blob/master/ukanren.lua#L53:L61 # # Additional reference for this function is scheme: # Ref for assp: http://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-4.html def assp(func, alist) - if alist && hd = car(alist) - func.call(hd) ? hd : assp(func, cdr(alist)) + if alist + first_pair = car(alist) + first_value = car(first_pair) + + if func.call(first_value) + first_pair + else + assp(func, cdr(alist)) + end + else + false end end - # A nicer printed representation of nested cons cells represented by Ruby - # Procs. - def print_ast(node) - if cons_cell?(node) - ['(', print_ast(car(node)), ' . ', print_ast(cdr(node)), ')'].join - else - case node - when NilClass, Array, String - node.inspect + # Converts Lisp AST to a String. Algorithm is a recursive implementation of + # http://www.mat.uc.pt/~pedro/cientificos/funcional/lisp/gcl_22.html#SEC1238. + def lprint(node, cons_in_cdr = false) + if cons?(node) + str = cons_in_cdr ? '' : '(' + str += lprint(car(node)) + + if cons?(cdr(node)) + str += ' ' + lprint(cdr(node), true) else - node.to_s + str += ' . ' + lprint(cdr(node)) unless cdr(node).nil? end + + cons_in_cdr ? str : str << ')' + else + atom_string(node) end end + + def lists_equal?(a, b) + if cons?(a) && cons?(b) + lists_equal?(car(a), car(b)) && lists_equal?(cdr(a), cdr(b)) + else + a == b + end + end + + private + + def atom_string(node) + case node + when NilClass, Array, String + node.inspect + else + node.to_s + end + end + end end