In addition to that, Lisps are sufficiently flexible that before CLOS itself was developed people were extending Lisp in Lisp to try out different object oriented models that fed into what became CLOS. That's hard to accomplish in most other languages, if it's even possible without going to a third party tool or digging into the compiler itself.
Any recommendations on good resources for learning Lisp to a degree that this program is understandable?
But here is Norvig's Python eval for a Lisp:
def eval(x, env=global_env):
"Evaluate an expression in an environment."
if isinstance(x, Symbol): # variable reference
return env.find(x)[x]
elif not isinstance(x, List):# constant
return x
op, *args = x
if op == 'quote': # quotation
return args[0]
elif op == 'if': # conditional
(test, conseq, alt) = args
exp = (conseq if eval(test, env) else alt)
return eval(exp, env)
elif op == 'define': # definition
(symbol, exp) = args
env[symbol] = eval(exp, env)
elif op == 'set!': # assignment
(symbol, exp) = args
env.find(symbol)[symbol] = eval(exp, env)
elif op == 'lambda': # procedure
(parms, body) = args
return Procedure(parms, body, env)
else: # procedure call
proc = eval(op, env)
vals = [eval(arg, env) for arg in args]
return proc(*vals)
https://norvig.com/lispy.html (most of the way down that page)So, the first thing is, what's the essential difficulty versus the noise: Lisp has two features which enable the evaluator to work. The first is quotation, which means that you can put a little apostrophe before some code and then it saves that code as a data structure, rather than implicitly evaluating it. The second goes by the overfancy name “homoiconicity”, that data structure is actually just singly linked list consumed by “car” (“first”) and “cdr” (“rest”) operations.
You can focus on understanding those two aspects pretty quickly, and then there are many tutorials about building your own Lisp that will get you there in an afternoon, if you'd like.
Or, you can take the royal road to this expression, in all of its cheesy 1980s glory:
https://youtube.com/playlist?list=PLE18841CABEA24090
It's lecture 7A where this specific program gets explicitly dissected by Sussman, wearing a fez. If he seems familiar, you might have watched Strange Loop 2011’s “We Really Don't Know How To Compute”, https://youtu.be/HB5TrK7A4pI
Indirectly this also means that lisps are very close at hand for “I want to add a scripting language onto this thing but I don't want to, say, embed the whole Lua interpreter” and it allows you to store user programs in a JSON column, say. You also can adapt this to serialize environments so that you can send a read-only lexical closure from computer to computer, plenty of situations like that.
Aside from the most famous, you have things like this:
1. The heart of logic programming is also only about 50 lines of Scheme if you want to read that:
https://github.com/jasonhemann/microKanren/blob/master/micro...
2. Hygienic macros in Rust probably owe their existence to their appearance in Lisps.
C2 asks the same question here: https://wiki.c2.com/?LispShowOffExamples with answers like
3. The object model available in Common Lisp was more powerful than languages like Java/C++ because it had to fit into Lisp terms (“the art of the metaobject protocol” was the 1991 book that explained the more powerful substructure lurking underneath this object system), so a CL programmer could maybe use it to write a quick sort of aspect-oriented programming that would match your needs.
4. Over there a link shows how in 16 LOC you can implement a new domain-specific language to define and run finite state machines: http://www.findinglisp.com/blog/2004/06/automaton-cleanup.ht...