My journey in the land of Lisp has just started. I think there’s still a long road to “enlightenment”, but the following “revelations” have already blown my mind…


First Revelation: Lisp is like the Universe

A few years ago, I read Paul Graham’s The Roots of Lisp article. In it, he showed how one could start with a set of programming primitives and build any function based on them, leading to a full-fledged programming language. He wrote his text in PostScript format which I’ve converted to PDF below:

jmc.pdf

PG showed that only the following primitives are needed to create a programming language (I’m intentionally changing the Scheme/Common Lisp syntax by adding a Haskell-esque syntax):

1. QUOTE
quote :: Any → Any
(quote x) ; often abbreviated as 'x

2. CONS
cons :: (Any, List) → List
(cons x y)

3. ATOM
atom? :: Any → Bool
(atom? x)

4. CAR
car :: List[Any] → Any
(car x)

5. CDR
cdr :: List[Any] → List[Any]
(cdr x)

6. COND
cond :: (Bool, Any), ... → Any
(cond (p1 e1) ... (pn en))

7. EQ?
eq? :: (Any, Any) → Bool
(eq? x y)

We also need a way to define functions (so I guess we can count them as yet another primitive feature) using lambda expressions, and denote them with labels:

lambda :: Any, ... → Any
(lambda (x1 x2 ... xn)
				(<something>))

; label notation
(label f (lambda (x) (cons x '(5))))

This was my first encounter with lambdas, but more was about to come as you’ll see in the rest of this post.

PG provided the following function definitions based on the above primitives (it is legit Common Lisp code, you can try it out in SBCL).

; The Lisp defined in McCarthy's 1960 paper, translated into CL.
; Assumes only quote, atom, eq, cons, car, cdr, cond.
; Bug reports to [email protected].

(defun null. (x)
  (eq x '()))

(defun and. (x y)
  (cond (x (cond (y 't) ('t '())))
        ('t '())))

(defun not. (x) 
  (cond (x '())
        ('t 't)))

(defun append. (x y)
  (cond ((null. x) y)
        ('t (cons (car x) (append. (cdr x) y)))))

(defun list. (x y)
  (cons x (cons y '())))

(defun pair. (x y)
  (cond ((and. (null. x) (null. y)) '())
        ((and. (not. (atom x)) (not. (atom y)))
         (cons (list. (car x) (car y))
               (pair. (cdr x) (cdr y))))))

(defun assoc. (x y)
  (cond ((eq (caar y) x) (cadar y))
        ('t (assoc. x (cdr y)))))

(defun evcon. (c a)
  (cond ((eval. (caar c) a)
         (eval. (cadar c) a))
        ('t (evcon. (cdr c) a))))

(defun evlis. (m a)
  (cond ((null. m) '())
        ('t (cons (eval.  (car m) a)
                  (evlis. (cdr m) a)))))

**(defun eval. (e a)
  (cond
    ((atom e) (assoc. e a))
    ((atom (car e))
     (cond
       ((eq (car e) 'quote) (cadr e))
       ((eq (car e) 'atom)  (atom   (eval. (cadr e) a)))
       ((eq (car e) 'eq)    (eq     (eval. (cadr e) a)
                                    (eval. (caddr e) a)))
       ((eq (car e) 'car)   (car    (eval. (cadr e) a)))
       ((eq (car e) 'cdr)   (cdr    (eval. (cadr e) a)))
       ((eq (car e) 'cons)  (cons   (eval. (cadr e) a)
                                    (eval. (caddr e) a)))
       ((eq (car e) 'cond)  (evcon. (cdr e) a))
       ('t (eval. (cons (assoc. (car e) a)
                        (cdr e))
                  a))))
    ((eq (caar e) 'label)
     (eval. (cons (caddar e) (cdr e))
            (cons (list. (cadar e) (car e)) a)))
    ((eq (caar e) 'lambda)
     (eval. (caddar e)
            (append. (pair. (cadar e) (evlis. (cdr e) a))
                     a)))))**

I recommend reading his article for more information. The last function defined is eval. which evaluates valid Lisp code inside Lisp! This meta aspect of Lisp was also mentioned in the SICP course by referring to the following Escher drawing—as if eval and apply write each other:

Untitled

https://www.youtube.com/watch?v=OyfBQmvr2Hc

The fact that you can start with a few building blocks and make a whole programming language that allows you to run any computation there ever will be is in itself mind blowing. But did McCarthy design those primitives, or as PG puts it, he discovered them? As it turns out, those building blocks could themselves be broken down into smaller pieces. Think of it like atoms in the universe that can be broken into sub-atomic particles. Surprisingly, these particles were found decades ago by Alonzo Church, the inventor of [Lambda calculus](https://en.wikipedia.org/wiki/Lambda_calculus#:~:text=Lambda calculus (also written as,to simulate any Turing machine.) long before electronic computers even existed!!

Second Revelation: Lisp is a way of thinking