← the guideThe Compiler Age

§ 02 — Eras · 1958

LISP

code as data — the programmable programming language

Left: era context, features, and the 101 hello. Right: 3 core concepts, 3 deeper 201 lessons, the factorial specimen, and where LISP lives today — each column scrolls on its own.

creators
John McCarthy, 1958
status
alive · Common Lisp, Scheme, Clojure, and every language with lambdas
lineage
→ Scheme

The problem it solves

Numbers were easy for machines; symbols and recursion were not. LISP was built to compute with ideas — lists, functions, programs.

The problem it carries

The parentheses (“lots of irritating superfluous parentheses”), runtime costs that offended the era, and a thousand dialects of the same dream.

Key features

s-expressions
One syntax — a parenthesized list — serves as both program and data structure.
conditionals and recursion
if and cond plus defun make the function the unit of program, and recursion replaces the loop.
garbage collection
Allocation and reclamation handled by the runtime; the programmer never frees.
homoiconicity
Code is data you can build at run time and eval — the root of every macro system since.

101 — hello, world

Session one is the smallest program that still counts as speaking LISP: what every tutorial prints first, in the dialect that mattered when the language arrived (1958).

the first program1958
(format t "Hello, world~%")

101First contact — hello world and 3 ideas that define how LISP reads. 201 — 3 lessons on mechanisms you meet after the factorial specimen: the sharp edges practitioners actually use.

101 — core concepts

3 fragments, each naming a habit of mind in LISP. Read the note, then the code — together they are the 101 in one sitting.

01 — s-expressions

One syntax for code and data: the program can read, build and run its own code.

(+ 1 (* 2 3))          ; prefix, fully parenthesized
(list 'a 'b 'c)        ; data...

02 — car, cdr, recursion

Lists are pairs; walking them taught the world recursion.

(defun len (xs)
  (if (null xs) 0
      (+ 1 (len (cdr xs)))))

03 — eval & quote

Quote suspends evaluation; eval resumes it — metaprogramming in two primitives.

(eval (list '+ 1 2))   ;=> 3
'(+ 1 2)               ; the code, unevaluated

201 — going deeper

The 201 assumes you have read the 101 and the specimen. Each lesson is one mechanism — what it is for, how it looks in code, and the trap or payoff that makes LISP distinctive at scale.

  1. macros
  2. higher-order functions
  3. the condition system

macros

defmacro writes code that writes code, with backquote and comma controlling what is evaluated when. Every Lisp-family macro system descends from this.

(defmacro unless (test &body body)
  `(if ,test nil ,@body))

(unless (null xs)
  (car xs))

higher-order functions

Functions are values: mapcar, reduce and funcall pass behaviour around instead of data. The functional core of Lisp is its calling convention.

(reduce + '(1 2 3 4))      ;=> 10
(mapcar #'1+ '(1 2 3))      ;=> (2 3 4)
(funcall #'+ 1 2)          ;=> 3

the condition system

Handlers bind to conditions, and restarts let a handler resume the computation from a chosen point — a control structure nothing else had in 1958.

(handler-case (error "boom")
  (error (e) (format t "caught: ~a~%" e)))

The specimen — factorial

The conditional, recursion, garbage collection — and code written as the very data structure it manipulates. Nine ideas for one language; all nine still load-bearing.

the conditional1958
(cond ((null xs) 0)
      (t (+ 1 (len (cdr xs)))))

Run it today

installbrew install sbcl

runsbcl --script fact.lisp

Where it is now

Descendants run airlines (Common Lisp), JVM shops (Clojure), and every lambda you have ever typed in JavaScript, Python or Rust.