This code was developed for the Clojure/conj 2017 presentation titled “The Dawn of Lisp, or: How to Write Eval and Apply in Clojure” which took place on October 13, 2017, at Baltimore, Maryland. You can also check the presentations’s Google slides and YouTube video.
The Lisp 1.5 manual, written by John McCarthy et al in 1961, contained in less than one page the compact yet amazing definition of the Lisp programming language using Lisp itself. This meta-circular account was referred as the “Maxwell’s Equations of Software” by Alan Kay. In a similar fashion, Paul Graham stated that this insight did to programming something like what Euclid did for geometry. In essence, the said definition demonstrated that it is possible to build an entire programming language using only a notation for functions and a handful of simple operators. In this talk, I will use Clojure to show how to build an interpreter that mimics Lisp in its very initial stages. As in the original documentation, the interpreter will consist of two main and highly intermixed functions: eval
and apply
. The central objective of this presentation is to provide attendees some highlights on the origins of Lisp and how its design ideas are central to Clojure and other programming languages.
-
acmqueue. A Conversation with Alan Kay. 2004.
-
Graham, Paul. The Roots of Lisp. 2002.
-
krisajenkins The Original LISP Interpreter In Clojure. 2012.
-
McCarthy, John. Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I. 1960.
-
McCarthy, John, et al. LISP 1.5 Programmer’s Manual, 2nd Edition. 1962.
-
McCarthy, John. History of Lisp. 1979.
NOTE: You need to have Leiningen intalled to run the code as described below.
After cloning this repository, move to the lisp-one-point-five
directory. At the terminal type:
cd lisp-one-point-five
Run the the REPL from there:
lein repl
Import the lisp-one-point-five.core
name space:
user=> (use 'lisp-one-point-five.core)
nil
You can now try expressions like:
user=> ($eval '(CAR L)
'((L (A B C))))
A
user=> ($eval '(CDR L)
'((L (A B C))))
(B C)
user=> ($eval '((LAMBDA (X) (CONS X (CONS X NIL)))
P)
'((P A)
(NIL ())))
(A A)
user=> ($eval '((LABEL MAPCAR (LAMBDA (F L)
(COND
((EQ L NIL) NIL)
(T (CONS (F (CAR L))
(MAPCAR F (CDR L)))))))
DUP
LST)
'((DUP (LAMBDA (X) (CONS X (CONS X NIL))))
(LST (A B C D))
(NIL ())
(T true)))
((A A) (B B) (C C) (D D))