Lisp in 32 lines of Ruby
blog.fogus.me
blog.fogus.me
It will compile to js and lua, and I'm focusing on writing games with it. I can attest that writing a Lisp compiler is really fun and shockingly simple in some places.
Current features I'm working on: http://jlongster.com/2012/01/16/outlet-gets-a-personality.ht...
shen is http://www.shenlanguage.org/
This seems like it would be perfect stuff for an educational lightning talk
If any of you are in the SF Bay Area, please consider doing a ~5 min presentation on your lisp-in-x implementation at the lisp meetup "revival" this saturday at the blackbox mansion in Atherton
...free beer... ;-)
http://www.meetup.com/balisp/events/48872022/ http://balisp.org/
I find it quite entertaining to see how specific language features allow for differing patterns. It is much more apparent with such Lisp implementations than with your typical Hello, World app or hidden by some library or framework.
1. Direct port of Peter Norvig's version in Python:
https://bitbucket.org/sainamdar/lisp2js/
2. Separate Syntactic Analysis from Execution:
But if you were to adopt a ruby syntax subset, enough of the semantics are similar enough to not pose a significant problem.
How easy is lisp to implement in a language without first class functions?
It gets ugly pretty quick though.
Economy class. :-)
In general, how do you write functions that return functions without some form of anonymous function? For instance, how do you write a function that takes an int a and returns a function that takes an int parameter and returns non-zero if and only if that parameter is greater than a?
Implementing Lisp in a language without first class functions is quite easy. Closure conversion is a simple process:
1) Find every variable in the parent lambda that is both accessed in a child lambda and assigned-to outside the child lambda; demote those variables to heap-allocated cells and rewrite references to those variables to indirect through the cell.
2) Note every free variable in the child lambda, and rewrite all references to those variables to indirect through an environment vector passed in through a hidden argument.
3) Generate each lambda as a top-level function, and generate each lambda expression as the allocation of a callable object referencing the top-level function and a heap-allocated environment vector; at each allocation site, generate code to copy the free variables into the environment vector.
This is literally the entire algorithm. It can be implemented in a couple of hundred lines of C.
What makes Ruby is all the sugar.
E.g. MRI 1.8.x has a parser alone that is about 6000 lines of Yacc with C actions and workarounds for Yacc limitations.
Your best bet for a semantic core of Ruby would probably seem closer to Smalltalk than to Ruby...
I think Ruby is a nicer language than Lisp.
[1] https://github.com/fogus/ulithp/blob/master/lithp.rb#L28
[1]: http://www-formal.stanford.edu/jmc/recursive/recursive.html
[2]: https://github.com/fogus/lithp/blob/master/src/core.lisp#L10...
I apologize for the dismissive rudeness of my first comment... I am tired of the many "I saved a function and its arguments into a list, and then wrote a method to evaluate that list" implementations which seem to be so exciting. Although I guess this isn't a new trend (see lisp in awk [1]).
(loop (print (eval (read))))[1]: http://en.wikipedia.org/wiki/Stalin_(Scheme_implementation)
l.eval [:label, :second, [:quote, [:lambda, [:x], [:car, [:cdr, :x]]]]]
No?I understand that (label second '(...)) makes second evaluate to that in the future, statefully, but, the lambda symbol doesn't even appear to have a definition; furthermore, if you try to use it in a way that would work with a real lambda, it doesn't work.
For instance [[:lambda, [:x], :x], 2]
self.eval @env[fn][2], Hash[*(@env[fn][1].zip args).flatten(1)]
It's triggered when the `fn` is not callable, i.e. when we pass in lambda: [:lambda, [:x], [:car, [:cdr, :x]]]
The code ignores the `:lambda` symbol (that would be `@env[fn][0]`).It evals the third element of the list (the lambda body) in a new context that combines `@env` and the binding of lambda's args to the symbols in the lambda's definition -- that's what the `Hash` mumbo jumbo creates.
[1]: https://github.com/fogus/ulithp/blob/b02d5806ce3b2d3766311c2...
:if => lambda { |(cond, thn, els), ctx| eval(cond, ctx) ? eval(thn, ctx) : eval(els, ctx) },
Seriously, any production code like that (very long line, cryptic variable names to make it fit better on said line) would get nasty review comments here.Why not put the whole thing a single line and have an even prettier page title?