Discover / Lisp and Scheme programming / Reading path

Best Books on Lisp and Scheme Programming, in Reading Order

@codesherpaBeginner → Intermediate
12
Books
142
Hours
4
Stages
Rate this path

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.

1

Thinking recursively

Beginner

Become 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

Key concepts
  • 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
You should be able to answer
  • 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?
Practice
  • 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.

The Little Schemer
Daniel P. Friedman · 1995 · 216 pp

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 seasoned schemer
Daniel P. Friedman · 1995 · 224 pp

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.

How to Design Programs
Matthias Felleisen · 2001 · 728 pp

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.

2

The great course

Intermediate

Work 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

Key concepts
  • 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
You should be able to answer
  • 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?
Practice
  • 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.

The Scheme programming language
R. Kent Dybvig · 1987 · 272 pp

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.

Structure and Interpretation of Computer Programs (SICP)
Harold Abelson · 1985 · 542 pp

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.

3

Common Lisp for real programs

Intermediate

Move 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

Key concepts
  • 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
You should be able to answer
  • 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?
Practice
  • 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.

Land of Lisp
Conrad Barski · 2010 · 482 pp

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.

Practical Common Lisp
Peter Seibel · 2005 · 500 pp

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.

ANSI Common Lisp
Paul Graham · 1996 · 432 pp

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.

4

Macros, metaprogramming and interpreters

Intermediate

Write 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

Key concepts
  • 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
You should be able to answer
  • 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?
Practice
  • 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.

On LISP
Paul Graham · 1993 · 413 pp

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.

Let  Over Lambda
Doug Hoyte · 2008 · 384 pp

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.

Paradigms of Artificial Intelligence
Peter Norvig · 1991 · 946 pp

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.

Lisp in Small Pieces
Christian Queinnec · 1996 · 524 pp

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.

Shares 1 book

Functional programming: a reading path to think in functions

Intermediate8books57 hrs3 stages
Shares 1 book

How to learn Programming

Beginner11books100 hrs4 stages
More on Game engine programming

Best Books on Game Engine Programming, in Reading Order

Beginner12books203 hrs4 stages
More on Scala programming

Learn Scala: the best books in order

Beginner6books43 hrs5 stages

More on lisp and scheme programming