Practical Common Lisp
Unlike other good books about Lisp, which are focused on a specific domain, like AI (such as Paradigms of Artificial Intelligence Programming ) or basic computer science (for example Structure and Interpretation of Computer Programs for the Lisp-like language Scheme), this book focuses on solving real-world problems in Common Lisp, like web programming, testing etc., after introducing the language by examples in the first chapters. I started with Lisp half an year ago, and it has helped me a lot in learning it. But even if you already know Lisp, this book may be useful for you, because it has a fresh view on the language and the examples in the later chapters are usable in your day-to-day work as a programmer.
The first chapter tells you something about the author (he was a good Java programmer before starting with Lisp) and the history of Lisp and Lisp dialects like Scheme. The next chapters are a tour through all Lisp features, written in easy-to-understand steps, beginning with the installation of a Lisp system and an introduction to the interactive REPL. You don't need any experience in other languages to understand it.
The general concept throughout is to explain a feature first, then show an example of how to use it, with detailed discussion of what the example does and possible pitfalls. A nice example is the APPEND function, which does not copy the last argument:
The reason most list functions are written functionally is it allows them to return results that share cons cells with their arguments. To take a concrete example, the function APPEND takes any number of list arguments and returns a new list containing the elements of all its arguments. For instance:(append (list 1 2) (list 3 4)) ==> (1 2 3 4)From a functional point of view, APPEND's job is to return the list (1 2 3 4) without modifying any of the cons cells in the lists (1 2) and (3 4). One obvious way to achieve that goal is to create a completely new list consisting of four new cons cells. However, that's more work than is necessary. Instead, APPEND actually makes only two new cons cells to hold the values 1 and 2, linking them together and pointing the CDR of the second cons cell at the head of the last argument, the list (3 4). It then returns the cons cell containing the 1. None of the original cons cells has been modified, and the result is indeed the list (1 2 3 4). The only wrinkle is that the list returned by APPEND shares some cons cells with the list (3 4). The resulting structure looks like this:
In general, APPEND must copy all but its last argument, but it can always return a result that shares structure with the last argument.
In chapter 9, the first larger practical example is developed, a unit testing framework (like JUnit), which is easy to use and to enhance.
Certain Lisp implementation behaviors can be confusing, such as those for for building pathnames. The pathname concept in Lisp is very abstract, leading to different choices in different implementations. This is no problem if you use only one implementation, but chapter 15 develops a portable pathname library, which works on many implementations. By doing this, it shows you how to write portable Lisp code, using different code for different implementations with reader macros.
After an introduction to the Common Lisp Object System (CLOS) and a few practical FORMAT recipes (the printf for Lisp, but more powerful), chapter 19, "Beyond Exception Handling: Conditions and Restarts", is really useful. The exception handling in Lisp (called "condition system") is more general than other exeption systems: In Lisp you can define restarts where you generate an exception and the exeption handler can call these restarts to continue the program. After reading this chapter, you'll never again want to use the restricted version of Java or C++ exception handling.
Chapters 23 to 31 show real world examples: a spam filter, parsing binary files, an ID3 parser, Web programming with AllegroServe, an MP3 database, a Shoutcast server, an MP3 browser and an HTML generation library with interpreter and compiler. If you ever thought that Lisp is an old language, only used for AI research, these chapters prove you wrong: Especially the binary files parser shows you, how you can extend the language with macros for implementing binary file readers, which looks nearly as clear and compact as the plain text binary file description itself. I'm using some of the ideas for a Macromedia Flash SWF file reader/writer I'm currently writing. Take a look at my Web page for my currently published Lisp projects.
The Web programming chapters demonstrates how to use a dynamic approach for generating web pages. You just start a Web server in your Lisp environment; then you can publish static Web pages or define functions, which are called when the page is requested by a browser. The author demonstrates how to define dynamic pages with formulars in Lisp and Lisp HTML generators.
After reading Practical Common Lisp, you will know most of Common Lisp and how to write real-world programs with it. Some special features, like set-dispatch-macro-character, or using one of the non-standard GUI libraries, are not explained, but it is easy to learn the rest of Common Lisp and to use other Lisp libraries, with the knowledge gained from this book.
You can purchase Practical Common Lisp from bn.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page
Now that I've your attention, let me tell you what I really think. :-)
Lisp syntax and style is awesome. I first learned Lisp a couple decades ago and I've never seen a language that is as expressive and *general* as Lisp. Every program I write in Ruby or Perl I think to myself "man, if this were Lisp I could just..." then I sigh and continue banging out code.
When I saw this book I thought it was pretty cool. Actually, it *is* pretty cool. I bought a copy as soon as the dead tree version was available.
But Lisp has some serious problems that need to be overcome before you'll see it get popular. Every time I bring them up I get flamed by the smug lisp weenies (SLW). But here goes.
1) There needs to be only one Lisp implementation. Every time a programmer or a book author suggests Lisp, he gives a *list* of implementations. This is no good. I only want to devote brain cells to exactly one implementation.
2) This one implementation needs to come with an elegant Lisp-ish standard library, with threads, Unix integration, process handling, web development, etc. Take a look at Ruby: it comes with RSS libraries, a *complete web server*, XML parser, integration with Unix, a thread library..etc.. If your Lisp implementation doesn't *at least* these things "out of the box", you lose (or rather, you continue to lose). Don't flame me and tell me how on Debian, you only had to install X Y Z and W. I'm not going to switch OS just to play with a language that doesn't pay the bills.
3) Legacy stuff has to GO. ANSI Lisp is chock full of crap. At least remove the deprecated stuff already. Just *remove* car/cdr already (or at least pretend they aren't there). Any terminology that doesn't match Unix, change it. If Unix calls it a file, stream, or process, you do the same. Sad but true.
4) Package system. asdf or whatever it is sucks. I don't know how to use it. It doesn't work reliably. It doesn't make sense. When I asked I get flamed. When it breaks and I ask what the error message means, I get flamed. When I point out the correct code to do what I want is inelegant and hard to remember, I get flamed. The other day I tried to load a testing framework into CLISP. It gave an obtuse error message. I googled for the error message and the only hit was an IRC chat log where three SLW's were pulverizing a newbie because he dared ask for help. After I gave up, I tried to install SBCL. It segfaulted during install and wouldn't finish (I'm on gentoo). I gave up again and went back to Ruby.
5) Community. Look at the Ruby community. Friendly, enthusiastic people. The Lisp community is full of bitter old souls (like me, heh).
There is only one solution to all this: somebody like a Matz or a Guido need to come along and make their own "UniLisp" and break from the ranks. Make a *truly* practical Lisp. Push at the expense of all these other Lisps. Rise to the top. Please, the programming world needs it. Everytime I see somebody doing something in another language that is SOOO easy in Lisp, I cringe. I wish I could tell them to start using Lisp, but I know it's not worth the trouble for 95% of the programmers out there. That's sad, because Lisp is really the ultimate general language.
"The advantage of car and cdr is that you can compose them into things like cdadr. Not that you should, except when you're in a hurry."
Thats a *disadvantage* as it is encouraging, er, 'wooly thinking'
What does 'contents of decrement address decrement register' mean? Nothing, thats what it means. It doesn't even refer to the way that the old LISP machine hardware worked.
Its a false mnemonic.
Besides which, just look at modern functional languages; its obvious that the excessive parenthisation in LISP is totally uneccesary.
They just couldn't write a parser for shit so they took the old adage "If in doubt, bracket" far too seriously and made it compulsory.
Ok theres also driving the 'everything-as-list' metaphor to absurdity, much as smalltalk did for object orientedness and prolog for logicness.
These were all experimental languages developed at a time when people were learning how to define, design and implement programming languages. This includes C and LISP.
We've learned a lot.
Its time to move on.
In the free world the media isn't government run; the government is media run.