Best Books on Lisp and Scheme Programming, in Reading Order
Lisp is less a language to add to a résumé than a way of thinking about programs as data, and the literature is unusually good because it was written by people trying to change how you think rather than to get you shipping by Friday. This path builds recursion and higher-order thinking with the Schemer books, works through Structure and Interpretation of Computer Programs, moves to Common Lisp for real programs, and ends with the macro and metaprogramming literature that is the reason Lispers never leave.
Thinking recursively
BeginnerBecome genuinely fluent in recursion, structural decomposition and higher-order functions, using nothing but s-expressions and a handful of primitives.
▸ Study plan for this stage
Pace: Eight to ten weeks for about 1,170 pages, but the page counts mislead badly here. The Little Schemer (216pp) is a two-column dialogue of questions and answers and can be finished in a week if you race — and racing wastes it. The right method is to cover the right-hand answer column with a card and a
- S-expressions: code and data share one representation, which is the fact the entire path is eventually built on even though the first book barely mentions it
- Structural recursion on lists — the null case, the car and the cdr — which The Little Schemer drills until it becomes reflex rather than technique
- The Ten Commandments the book accumulates, particularly the first (always ask null? first) and the ones about recurring on the cdr and building with cons
- Higher-order functions arriving in the last chapters as a natural consequence rather than as an advanced topic, culminating in the applicative-order Y combinator
- Accumulator passing and tail recursion in The Seasoned Schemer, and what it means for a recursive call to be in tail position
- letcc and continuations as the point where recursion stops being about lists and starts being about control, which is the genuinely hard step in the second book
- set! and the deliberate late introduction of mutation — both Schemer books withhold assignment for hundreds of pages, and the reason is pedagogical rather than ideological
- Felleisen's design recipe: data definition, contract and purpose statement, examples, template from the data definition, body, tests — a mechanical procedure that turns intuition into method
- Write a function that flattens an arbitrarily nested list, and explain which of the Commandments each line follows.
- What is a tail call, and how would you convert a naive recursive length function into a tail-recursive one? What changes about the space used?
- Explain the Y combinator as The Little Schemer derives it — what problem is it solving, and why does the derivation proceed in the steps it does?
- What does letcc capture, and what happens to the rest of the computation when you invoke a captured continuation?
- State the design recipe's six steps from memory, and apply them to a function over a binary tree.
- Why do both Schemer books delay set! for so long, and what changes about your reasoning once mutation is available?
- Read The Little Schemer with the answer column covered, answering every question aloud or in writing before revealing it. This is not optional advice; the book does almost nothing for a passive reader.
- Type every function from The Little Schemer into a REPL as you go and test it on cases the book does not use. Three or four of them break on inputs the dialogue never tries.
- Derive the Y combinator yourself, on paper, following the book's sequence of transformations. Then write it from scratch a week later without looking.
- Implement a small interpreter for arithmetic expressions represented as nested lists. It takes an hour and it is a preview of the metacircular evaluator two stages away.
- Work at least one full exercise set from each part of How to Design Programs, following the recipe steps explicitly rather than jumping to the body. Writing the template before the body feels pointless until the third time it saves you.
- Take a function you have already written in another language and redo it by the recipe, starting from the data definition. Note where the recipe would have prevented a bug you actually had.
Next up: You can now decompose problems recursively and design from the data outward; the next stage takes those habits into a full curriculum that ends with you writing an interpreter for the language you are writing in.

A hundred pages of questions and answers that rebuild your intuition for recursion from scratch. It looks like a toy and is not; almost everyone who succeeds with the rest of this path starts here.

The direct sequel, taking the same method into continuations, letrec, set! and state. Read immediately after — the format is identical and the difficulty step is deliberate.

Turns the intuition into method: a systematic design recipe that goes from data definition to tested function. It supplies the discipline the Schemer books teach playfully.
The great course
IntermediateWork through the classic MIT curriculum — abstraction, data-directed programming, state, streams, and building interpreters and a register machine — and come out able to read any Scheme code.
▸ Study plan for this stage
Pace: Four to six months for about 814 pages, and this is the slowest page count in the path by a wide margin because SICP is exercises, not prose. The Scheme Programming Language (272pp) is a reference — read the first few chapters properly, then keep it open. Structure and Interpretation of Computer Pro
- Procedural abstraction and the substitution model of evaluation, and the distinction between a recursive process and a recursive procedure — a linear iterative process can be written with a recursive-looking call
- Data abstraction and the closure property: constructors and selectors, and the point that a pair is enough to build anything
- Data-directed programming, message passing and generic operations — the dispatch table in Chapter 2 is object orientation derived rather than assumed
- Chapter 3's assignment and the environment model, and Abelson and Sussman's careful account of what mutation costs you: referential transparency, and the substitution model itself
- Streams and delayed evaluation as an alternative to state, and the specific difficulty of Chapter 3's stream exercises
- The metacircular evaluator: a Scheme interpreter written in Scheme, in a few pages, where eval and apply call each other. This is the conceptual centre of the whole path
- Variations on the evaluator — lazy, non-deterministic with amb, and the logic-programming interpreter — which show that a language's semantics is something you can edit
- The register machine and the explicit-control evaluator in Chapter 5, which lower the whole thing to a machine and close the gap between the elegant model and real execution
- What is the difference between a recursive procedure and a recursive process? Give a procedure that looks recursive and generates an iterative process.
- Explain the closure property of a data-combination method and why it matters that cons can hold pairs.
- What does the environment model explain that the substitution model cannot, and at what point in the book does the substitution model stop working?
- Write eval and apply from the metacircular evaluator from memory, in outline. If you cannot, you have not finished Chapter 4.
- What does amb do, and how is the non-deterministic evaluator implemented in terms of continuations or failure continuations?
- In Chapter 5, what does the explicit-control evaluator make visible that the metacircular one hides?
- Do the exercises. This is the whole instruction for this stage — SICP read without exercises is a different and much weaker book. Aim for most of Chapters 1, 2 and 4, and as much of 3 and 5 as you can sustain.
- Implement the metacircular evaluator from scratch, without the book open, after you have read Chapter 4 once. It will take a day and it is the single most valuable exercise in this path.
- Extend your evaluator with one feature the book does not add — let* as a derived form, or a simple tail-call optimisation, or dynamic scoping as an experiment. Editing a language's semantics for the first time is the moment the path pays off.
- Do the picture language exercises in Chapter 2. They are the most fun in the book and they demonstrate closure under combination better than any prose could.
- Implement the stream-based prime sieve and then rewrite one stateful program you have written before as a stream program. The comparison is Chapter 3's argument in concrete form.
- Use Dybvig to answer three questions SICP leaves open about the actual language. Learning to reach for a specification is a habit worth forming here.
Next up: You have built an interpreter and know what a language is made of; the next stage moves to a much larger industrial Lisp where you can write programs people use, and where the macro system is a first-class part of the language rather than an exercise.

A compact, precise reference for the language itself, so you are not fighting syntax and library questions while wrestling with hard ideas. Keep it beside you for the next book.

The central text of this path and one of the great books in computing. Its metacircular evaluator and register machine make the language's self-describing nature concrete, which is exactly what the macro literature later exploits.
Common Lisp for real programs
IntermediateMove from an academic Scheme to an industrial Lisp — packages, CLOS, conditions and restarts, the REPL-driven workflow — and write software you would actually ship.
▸ Study plan for this stage
Pace: Three to four months for about 1,414 pages. Land of Lisp (482pp) is illustrated, jokey and fast — three weeks, working the games. Practical Common Lisp (500pp) is the workhorse: read it project by project, building each one, over a couple of months. ANSI Common Lisp (432pp) is tighter and more opini
- Lisp-2 versus Lisp-1 — Common Lisp keeps function and variable namespaces separate, which is why funcall and sharp-quote exist and why macro hygiene works differently from Scheme's
- The REPL-driven workflow as the actual product of this stage: redefining functions in a running image, inspecting live state, and recompiling a single function without restarting
- The condition system, which is the most underappreciated thing in the language: conditions, handlers and restarts separate the decision about what to do from the place the problem was detected
- CLOS as a different object model from the class-centric mainstream — generic functions dispatching on multiple arguments, method combination, and before, after and around methods
- Packages and symbols, and why symbol interning matters once you are writing macros
- defmacro and the backquote reader syntax, introduced here as a working tool rather than as a theory, with Seibel's practical examples showing when reaching for a macro is warranted
- Seibel's project structure as the pedagogy: the spam filter teaches sequences and data handling, the ID3 parser teaches binary I/O and macro-generated parsers, the MP3 server teaches packages and libraries
- Graham's stylistic argument in ANSI Common Lisp — bottom-up programming, small utilities, and building the language up toward the problem rather than the program down toward the language
- What does it mean that Common Lisp is a Lisp-2, and what does it change about how you pass functions around?
- Explain the condition system's separation of handler from restart, and give an example where that separation lets you recover in a way try-catch cannot.
- How does CLOS dispatch differ from single-dispatch object orientation, and what problem does method combination solve?
- In Seibel's ID3 parser, what is the macro actually generating, and why is a macro the right tool there rather than a function?
- What is the practical difference between developing against a live image and a conventional compile-and-run cycle? Name three things you can do that you could not before.
- What does Graham mean by bottom-up programming, and how does it show up concretely in the way his code is factored?
- Get SBCL and SLIME working and make yourself use the REPL properly for a week — redefine functions in place, use the inspector, recompile single top-level forms. The workflow is the deliverable.
- Build one of Land of Lisp's games and then extend it with a feature the book does not include. Extending someone else's Lisp code is a distinct skill from writing your own.
- Work Seibel's ID3 parser project fully, including the macro that generates the binary-format readers. It is the best worked example of macro-as-tool in print.
- Write a small library with proper package definitions, exported symbols and an ASDF system definition. Packaging is the part most self-taught Lispers skip and then trip over.
- Implement one error path using conditions and restarts rather than return codes or exceptions, and write down what the restart-based version lets a caller do that the alternatives do not.
- Define a CLOS protocol with a generic function specialised on two arguments, and add an around method that logs. Multiple dispatch is easiest to appreciate by building something that needs it.
Next up: You can write and ship real Lisp, and you have used macros as a tool; the last stage treats macros as the point — extending the language itself, and then implementing the language from the ground up.

A deliberately unserious entry to Common Lisp built around writing games, which is the fastest way past the initial strangeness of a much larger language than Scheme.

The book that made Common Lisp approachable again: real projects — a spam filter, an ID3 parser, an MP3 server — teaching packages, macros, CLOS and the condition system as they become necessary.

Graham's tighter, more opinionated survey of the same language, strong on style and on why Lisp programs are structured the way they are. Read after Seibel, as preparation for his next book.
Macros, metaprogramming and interpreters
IntermediateWrite macros that extend the language itself, judge when doing so is warranted, and understand how Lisps are implemented well enough to build one.
▸ Study plan for this stage
Pace: Six months or more for about 2,267 pages, and this stage is open-ended by design. On Lisp (413pp) should be worked chapter by chapter over two months, implementing the utilities as you go. Let Over Lambda (384pp) is shorter and much stranger — a month, read critically. Paradigms of Artificial Intell
- Macroexpansion time as a separate phase, and the discipline of knowing what exists at expansion time versus at run time — the source of nearly every macro bug
- Variable capture and the gensym discipline: unintended capture, the free-symbol capture case, and why Common Lisp's unhygienic macros put the burden on the author
- Graham's bottom-up thesis in full: write utilities until the language fits the problem, and judge a macro by whether it buys something a function could not
- The rule for when a macro is warranted — control of evaluation, new binding forms, or compile-time computation — and Graham's own warnings about using them when a function would do
- Anaphoric macros as deliberate capture, which Graham introduces carefully and Hoyte pushes much further
- Hoyte's read macros and macro-defining macros, and the honest framing: Let Over Lambda deliberately goes past what most working Lispers consider prudent, and its value is in showing where the edge is, not in prescribing daily practice
- Norvig's reimplementations — Eliza, GPS, a pattern matcher, a Prolog interpreter, a Scheme compiler — as a demonstration that a language with macros can host other languages
- Queinnec's sequence of eleven interpreters, each isolating one semantic decision — scoping, environments, control, continuations — so that language design becomes a set of independent choices rather than a package
- What is variable capture, what are the two kinds, and how does gensym address one of them?
- State Graham's criteria for when a macro is justified, and give an example of a macro you have seen that should have been a function.
- What does an anaphoric macro do, and what is the argument for and against deliberate capture?
- In Norvig's Prolog implementation, what parts of Prolog's semantics does the host language provide for free and what has to be built?
- Take two of Queinnec's interpreters and name the single semantic decision that differs between them.
- After the whole path: what can you do in Lisp that you genuinely cannot do in a language without macros, and what is the honest cost of that capability?
- Implement every utility in On Lisp yourself before reading Graham's version, then compare. The gap between your version and his is the most useful feedback in the stage.
- Write a macro that captures a variable unintentionally, then diagnose it with macroexpand-1. Producing the bug deliberately is how the failure mode becomes recognisable.
- Implement a pattern matcher following Norvig, then use it to build a small Eliza. It is a weekend and it shows what symbolic programming feels like.
- Work Norvig's Prolog interpreter through to running queries. Hosting a logic language inside Lisp is the clearest possible demonstration of the path's thesis.
- Implement Queinnec's first three interpreters yourself, changing one semantic decision each time — dynamic versus lexical scope, then first-class continuations. Each rewrite is short and each teaches one thing exactly.
- Finally, write a small language of your own with a Lisp-derived syntax and a semantics you chose deliberately, and write a page justifying each choice. That page is the deliverable of the whole path.
Next up: This is the end of the path — recursion, the great course, an industrial Lisp and the metaprogramming literature — and the natural next step is to reread The Little Schemer, which takes an evening and reads entirely differently once you have written an evaluator that could run it.

The canonical treatment of bottom-up programming and macros — utilities, anaphoric macros, continuation-passing style. This is the book the whole path has been preparing you for.

Picks up where On Lisp stops and pushes macrology to its limits, including read macros and anaphora most Lispers consider excessive. Valuable precisely because it shows you the edge of the technique.

Norvig rebuilds the classic AI programs — Eliza, GPS, a Prolog interpreter, a Scheme compiler — in Common Lisp, and it doubles as the best book on large-scale Lisp program design and optimisation.

The deep end: eleven interpreters and two compilers, treating evaluation semantics, scoping and continuations rigorously. Read last, when you want to understand Lisp implementation rather than use it.
Discussion
Keep reading
Paths that share books, cover the same subject, or open a related topic.