ANSI Common Lisp
Lisp promises something most programming books don't: not just syntax, but a different way of thinking. *ANSI Common Lisp* makes this promise explicitly and delivers on it better than almost any other book in the language's long bibliography.
Graham structures the book as two things at once: a tutorial that builds from basic expressions through closures, macros, and the Common Lisp Object System, and a reference appendix that covers every operator in the ANSI standard. The combination works because the tutorial half earns the reference half — by the time you reach the appendix, you've already seen most of the language in action. The density is high. Every chapter works. The prose is clear without being condescending, and the examples are genuinely interesting rather than contrived: a backward-chainer, an HTML generator, a complete object-oriented language written in Lisp itself. That final chapter is the best argument in the book — by building OOP from scratch, Graham shows you what the abstraction actually is rather than what it happens to look like in Java.
Where the book shows its age, or more accurately its author's aesthetic preferences, is in the coding style. Graham is a committed functionalist. He avoids `loop`, prefers recursion where iteration would be cleaner, uses terse names, and generally guides readers toward a subset of Common Lisp that reflects his own tastes more than the language's strengths. For a learning resource this has an upside — it forces you to think in terms of recursion and higher-order functions, which trains important muscles. But it also installs biases that take time to unlearn. Common Lisp is *not* a functional-first language the way Scheme or Haskell are; it was designed for pragmatic iteration and mutation as much as for recursion and purity. The `loop` facility, which Graham barely touches, is in production Common Lisp code everywhere. A reader who finishes this book may feel they've learned Lisp when they've really learned Paul Graham's Lisp.
Still, the gaps are less damaging than they sound. The fundamentals — symbols, closures, macros, the interaction between code and data — are covered with a clarity that other books rarely match. The macro chapter alone is worth the price. And the philosophical argument running through the whole text, that shaping the language to fit the problem is the right way to write programs, is one of the more useful ideas in software engineering. You may not agree with every choice Graham makes, but you'll understand them, and understanding why someone reasons the way they do is more valuable than a neutral survey of features.
As an introduction to Common Lisp, it still holds up thirty years later — with the caveat that you'll want to follow it with time in a REPL and exposure to more idiomatic modern code. As a way of learning to think about programs, it remains one of the sharpest books in the field.