68 lines
3.5 KiB
Markdown
68 lines
3.5 KiB
Markdown
I've been working my way through a Lisp textbook, *Lisp In Small
|
||
Pieces*, by Christian Quinnec. It was originally written in French and
|
||
is not that well known among English-speaking Lisperati, not in
|
||
comparison to the Wizard book or Paul Graham's *On Lisp*, but what
|
||
caught my attention was how it really was in *small* pieces. Each
|
||
chapter ended with an interpreter described, sometimes in code,
|
||
sometimes in text; if you were smart enough, you could actually piece
|
||
the whole thing together and see how it worked.
|
||
|
||
I decided to make things hard for myself. Since I'm *not* a Lisperati
|
||
(although I may well and truly be seduced by Hy), I decided to make
|
||
things hard for myself by writing the interpreter in Coffeescript. Most
|
||
Lisp books assume you have a Lisp handy, and Quinnec's examples are fine
|
||
and dandy on many variants of Scheme, but for a fun time I decided to
|
||
write it in something else. Raganwald claims Javascript "is a Lisp,"
|
||
and if that's so it ought to be good enough to write a Lisp in it.
|
||
|
||
I mean, it's obviously been done before. I tried once before but got
|
||
lost. *LiSP* does me the favor of keeping me on track.
|
||
|
||
You can see all my sourcecode at <a
|
||
href="https://github.com/elfsternberg/LispInSmallPieces">Github: Lisp In
|
||
Small Pieces</a>.
|
||
|
||
Chapter 1 contains the base interpreter. It also contains a
|
||
hand-written Lisp reader, and refers to another project I have on
|
||
GitHub, <a
|
||
href="https://github.com/elfsternberg/cons-lists">cons-lists</a>, which
|
||
is exactly what it sounds like, a singly-linked list implementation in
|
||
Javascript, using nested Javascript arrays as the base. The base
|
||
interpreter is very primitive-- you can't even create new variable names
|
||
in the global namespace! Although you can shadow them using lambdas, so
|
||
it's pretty much bog standard Lambda Calculus.
|
||
|
||
Chapter "Lambda 1" contains a continuation-passing variant of the
|
||
interpreter from Chapter 1. It's basically a facile reading of
|
||
Lisperator's λ-language intepreter, with my own parser front-end and
|
||
some CPS style. It passes all the tests, but it's a distraction.
|
||
|
||
Chapter 3 contains the same interpreter, only using the architecture
|
||
Quinnec describes in Chapter 3 of his book.
|
||
|
||
Chapter 2 describes a number of different methodologies for binding,
|
||
scoping, and namespaces. The material is interesting but I didn't
|
||
pursue writing the various interpreters. I "got" what Quinnec was
|
||
saying, and if I'm ever interested in writing something with scoping
|
||
rules outside of the lexical scopes with which I'm familiar, I might
|
||
revisit the material.
|
||
|
||
The next step will be to add functions to the Chapter 3 interpreter to
|
||
do the various continuation management games, like call/cc, throw/catch,
|
||
$and so forth. Because *those*, I feel I need to understand.
|
||
|
||
How far will I take this project? I’m not sure. Chapter 4 is
|
||
"Assignment and Side Effects," so I’ll do that. Chapter 5 is theory,
|
||
and 6 implementation, of a "fast interpreter" of the kind French
|
||
programming language guys apparently love to study. I’ll read them, but
|
||
I’m not sure what code I’ll generate out of that. Chapter 7,
|
||
"Compilation," is interesting in that he starts by defining a VM that on
|
||
top of which our bytecode will run, and implement both the VM and the
|
||
compiler in Scheme. I think I want to do that chapter, and then
|
||
re-write the compiler to create LLVM-compatible code instead, just to
|
||
learn LLVM. Chapter 8 implements EVAL, chapter 9 has Macros, and
|
||
chapter 10 has Object-Oriented Lisp. So I’ll probably do those as well.
|
||
|
||
And then... we’ll see. I surprised myself by doing Chapter 3 in less
|
||
than two weeks.
|