On Fri, 09 Jul 2004 10:52:17 +0000, gabriele renzi wrote: > > usually people seem to think that ruby is smalltalk or lisp or perl > done properly. Probably all of this are just unlambda done properly :) FYI, I have written a unlambda interpreter in Ruby. (I don't know if I should be proud of it...) It was ridiculously easy, because Ruby already provides everything (continuations, closures,...). I think the implementation is even easier to understand than the spec. It is not a very efficient implementation, since it uses recursion. But you don't have very large unlambda programs that you absolutely need to run, do you? Here it is: (Don't continue reading if you don't want to waste your time...) #!/usr/bin/env ruby #Unlambda interpreter #written by Kristof Bastiaensen <kristof.bastiaensen / vleeuwen.org> require "stringio" def readchar $char_read = getc end K = lambda {|a| lambda { |b| a }} S = lambda {|a| lambda { |b| lambda { |c| a[c][b[c]] }}} I = lambda { |a| a } V = lambda { |a| V } R = lambda { |a| puts; a } C = lambda { |a| callcc { |cc| a[cc] } } D = lambda { |a| a} AT = lambda { |a| (readchar() ? a : V ) } PIPE = lambda { |a| $char_read ? a[$char_read] : V } CharLookup = { ?k => K, ?s => S, ?i => I, ?v => V, ?r => R, ?c => C, ?@ => AT, ?| => PIPE, ?d => D, ?e => :dummy } def compile(stream) loop do raise "Premature end of stream!" if stream.eof ch = stream.getc if ch == ?` #` return [compile(stream), compile(stream)] elsif ch == ?. a = stream.getc return lambda { |b| print a.chr; b } elsif ch == ?? a = stream.getc return lambda { |b| b == a ? a : V } elsif CharLookup.member?(ch) return CharLookup[ch] end end end def eval_expr(expr) if expr.class == Array r = eval_expr(expr[0]) e2 = expr[1] if (r == D and e2.class == Array) return lambda { |a| eval_expr(e2)[a] } else return r[ eval_expr(e2) ] end else return expr end end def eval(string) string = string.gsub(/#.*$/, "") stream = StringIO.new(string, "r") callcc do |exit| CharLookup[?e] = lambda { |a| exit[a] } tree = compile(stream) eval_expr(tree) end end if(ARGV.length != 1) $stderr << "Usage: %s <unlambda file>\n" % $0 else str = IO.read(ARGV[0]) eval(str) end