From: Elliott Hird Date: 2008-03-02T01:59:59+09:00 Subject: a practical Lisp in Ruby Hi! I've been working on a Lisp interpreter in Ruby that is fully integrated (I mean -- fully. The aim is to have basically nothing specific to the interpreter and use Ruby for everything. Basic rule of thumb: you should be able to use it to write a Rails app with no extra pain than in Ruby.) Some examples: '(1 2 3) => (1 2 3) [1 2 3] => [1 2 3] ([] empty?) => true (puts (if ([] empty?) "hello world" "oh no")) => hello world Now, I hope to have some code released Real Soon Now (it really isn't usable enough yet; needs some reworking). But I'd like the Ruby community's opinion on some few things, to try and make it as Ruby-ish as possible. So, dump of things I've thought about: - should # be used as a comment marker (instead of ;)? it might get in the way of *something*, lisp dialects tend to use it a lot, but #\c will probably be ?c, #t/#f is true/false, and #(...) is [...] so I'm not sure. - should 'a be ruby's :a? that could mess up pretty printing, e.g.: '(a b c) => (:a :b :c) if 'a is something other than :a, what should it be? a subclass of Symbol that just overrides pretty-printing, i guess. and then :a would be ruby's :a. - syntax for dicts? if we take the above idea, I think something like: {:a 2 :b 3} => {:a => 2, :b => 3} would be nice, but again there's the problem that pretty-printing loses out. however I don't think that Ruby's syntax should be re-used directly, because it's not lisp-like. - how to call out to ruby. what happens if you pass a list to a ruby function? I could recursively translate them to arrays, but that's expensive and if you're calling out to something that wants to directly use the object or is one of the functions that doesn't care what type its object is, it might not even be expected behaviour. also, should i translate a_b to a-b? vise-versa? - on a similar note, what class is (lambda (x) x)? if a Proc I have to have a trampoline in the Proc, which isn't nice. a subclass of Proc? - how to handle blocks. some ideas: ([1 2 3] map (lambda (x) (+ x 1))) that means I have to do arity stuff, and presents a problem -- what if 'map' there was variadic? are we passing a function, or a block? ([1 2 3] map (do (x) (+ x 1))) here 'do' creates something internally treated as a block. again the variadic problem, relating to my "what if the func/method doesn't care about the type it gets"? ([1 2 3] map do (x) (+ x 1)) this is a little bit hard to read, but unambigious. of course, now you can't use "do" in most places. a multiline example of this: ([0 1 2 3 4 5] map do (x) (if (= (% x 2) 0) (+ x 5) (- x 4))) this is my preferred syntax at the moment, actually. maybe i could hijack {...} somehow (don't really like that idea). - (def (func ...) ...) or (def func (...) ...)? the former seems more rubyish to me, i guess. (def (foo) ...) instead of (def foo () ...). - this thing: >> foo = 3 => 3 >> def foo; 4 end => nil >> foo => 3 >> method(:foo).call => 4 since this thing will emulate a Lisp-1 (basically), how should this be handled? maybe in the same way. - and closely linked to that: since a 0-arg function is used often in Ruby in place of a variable (but -- mostly in a method, where this would be (obj foo) so it wouldn't be a problem). you'd have to do (foo) currently, which would differenciate it from foo. - also related: watch this imaginary session in the Lisp REPL >> (def foo 3) => 3 >> (def (foo) 4) => # >> foo => 3 or #?! >> (foo) => "you can't call a Fixnum!" or 4? this clashes with Lisp-1-ness, certainly. Anyway, that's the end of this long post for now. Feel free to ignore my ramblings, but to leave, here's a few code examples that don't actually work right now and may look completely different when they do :-) ;; Output "I love Ruby" (def say "I love Ruby") (puts say) ;; Output "I *LOVE* RUBY" (set! (say "love") "*love*") ;; set! name? (puts (say upcase)) ;; Output "I *love* Ruby" five times (5 times do (puts say)) and the second: (class Numeric (def (plus x) (self + x) ;; or (the same, but variadic) (+ self x))) Well, OK. Have a third. (def search-engines (%w[Google Yahoo MSN] map do (engine) (+ "http://www." (engine downcase) ".com"))) -ehird