The overwhelming impression that Peter Seibel's book Practical Common Lisp left on my mind was that it had been written by someone who cares as much about the art of programming as he does for the craft of writing well. In fact, there is an intriguing self-admission by Seibel in that book's About the Author section where he notes
Peter Seibel is either a writer-turned-programmer or a programmer-turned-writer. After picking up an undergraduate degree in English and working briefly as a journalist, he was seduced by the Web...
And wow, does his command of both Lisp and writing shine throughout the book! Finally, in the Where to Go Next section of Practical Common Lisp, Seibel points out that
Two books that cover general Common Lisp technique are Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp by Peter Norvig (Morgan Kaufmann, 1992) and On Lisp: Advanced Techniques for Common Lisp by Paul Graham (Prentice Hall, 1994). The former provides a solid introduction to artificial intelligence techniques while teaching quite a bit about how to write good Common Lisp code, and the latter is especially good in its treatment of macros.
I have copies of both of these preceding excellent books. While both are replete with good advice on programming, it is Paul Graham's On Lisp that also has the distinction of having been written spectacularly well; it has to be read to be believed! Noting briefly that the two other books by Graham (I own and have read the copy each of those first-class books) are:
- ASNI Common Lisp (Prentice Hall)
- Hackers & Painters: Big Ideas from the Computer Age (O'Reilly)
When Graham's Hackers & Painters came out, many years ago (it predates my reading any of his works on Lisp), I was so impressed by its quality that I wrote to him, telling him how highly I thought of his book, plus recommending to him the best book available on this planet on writing well, namely Writing with Style: Conversations on the Art of Writing by John R. Trimble. Graham graciously replied to me, saying that he in fact had a copy of Writing with Style in his bookshelf. I was pleasantly surprised, because while most everyone has heard of The Elements of Style (by Strunk and White), hardly anyone is even aware of John R. Trimble's stellar gem of a book. In my mind at least, and with all due respect to the former book (because I have read and appreciated its advice), Writing with Style is the book that The Elements of Style wants to be when it grows up...
I wish to to add here that Graham's Hackers & Painters uses the word hacking in the fine and true connotations it is meant to carry, when applied to the art of computer programming:
At any rate, I'll leave to you the reading of the fine books that I mention above. Meanwhile, if only to convey a flavor of the stellar book that On Lisp is, here is an excerpt from that book. In particular, do look for the sublime metaphors that Graham uses in the second of the following two paragraphs with the cue sentence Language and program evolve together:
...The traditional approach is called top-down design: you say “the purpose of the program is to do these seven things, so I divide it into seven major subroutines. The first subroutine has to do these four things, so it in turn will have four of its own subroutines,” and so on. This process continues until the whole program has the right level of granularity—each part large enough to do something substantial, but small enough to be understood as a single unit.
Experienced Lisp programmers divide up their programs differently. As well as top-down design, they follow a principle which could be called bottom-up design—changing the language to suit the problem. In Lisp, you don’t just write your program down toward the language, you also build the language up toward your program. As you’re writing a program you may think “I wish Lisp had such-and-such an operator.” So you go and write it. Afterward you realize that using the new operator would simplify the design of another part of the program, and so on. Language and program evolve together (italics are mine). Like the border between two warring states, the boundary between language and program is drawn and redrawn, until eventually it comes to rest along the mountains and rivers, the natural frontiers of your problem. In the end your program will look as if the language had been designed for it. And when language and program fit one another well, you end up with code which is clear, small, and efficient.