Slashdot Mirror


Practical Common Lisp

Frank Buss writes "Common Lisp is an ANSI standard, which defines a general purpose language and library, and is implemented by free and commercial compilers and IDEs; see *hyper-cliki* for more general information about Common Lisp. The book Practical Common Lisp explains the language with many practical examples and is available in full text online, too." Read on for the rest of Buss' review. Practical Common Lisp author Peter Seibel, Gary Cornell (Editor) pages 500 publisher Apress rating 8 reviewer Frank Buss ISBN 1590592395 summary A book for learning and using 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

12 of 617 comments (clear)

  1. LISP is amazing. by millennial · · Score: 5, Interesting

    I took a Programming Languages course up at Michigan Tech a couple years back. We wrote our own interpreter using nothing but Common LISP, and it blew my mind. It got me really interested in programming language design.
    However, LISP can also be hard to learn. The function names don't make sense to most people who have been raised on higher-level (1980s+) languages. I mean, 'car' to grab the first element of a list, and 'cdr' to grab all the others? It can get downright confusing sometimes.

    --
    I am scientifically inaccurate.
    1. Re:LISP is amazing. by haystor · · Score: 5, Informative

      Ok, first imagine what it would take to add something to a language like Java. Let's take try/catch/finally as an example. You might have some java code that works like:

      try {
      methodCall();
      } catch (Exception e){ //TODO: we'll clean this up later
      } finally {
      otherMethodCall();
      }

      Now let's say I wanted something like try/catch only specifically geared toward database transactions. I want it to look like this:

      tran { //db operations go here
      } rollback { // code handling rollback
      } success { // code specific to a successful transaction
      }

      You just can't do that. Sure you could get similar functionality through the use of try/catch and a bunch of helper functions, but you can't integrate it straight into the language itself. You can only add to the language's library. In LISP, there is no real difference.

      I can implement a "tran" macro so I can do things like:

      (tran (withdraw 25.00 from-account)
      (deposit 25.00 to-account) :rollback #'rollback))

      This particular instance is my favorite example. It may not seem like a big deal, but I have hundreds of these things that aren't a big deal in my code. If I think something can be done a better way in the language I can add it.

      The tran macro would be expanded during runtime to something that looks more like:

      (begin-tran)
      (withdraw...)
      (deposit...)
      (end- tran) or (rollback) depending on what happened.

      A more complicated version of this macro could take into account nested versions of itself.

      Someone will say that try/catch can be made to accomplish what I want. Yes it can. Those same people won't admit however that Perl can be bent to do what Java does.

      There is a lot of writing about how great it is to have macro expansion at runtime. That was always meaningless to me until I latched on to that "tran" example above. All of a sudden I realized I wasn't bound to passing values (or references to values, essentially the same thing) to a function. Now I could pass whole chunks of code around. This struck me as such a right thing to do. I'd always been bugged that all the Java consultants around me were memorizing patterns. If something is a pattern, shouldn't the computer be doing it? LISP told me that yes, the computer should be doing it, not that I should be writing pages of patterned code.

      It took me a year of talking to one of the guys I worked with where I explained macros to him. Six months after I left that place we went to lunch and he told me he finally saw the light as he was cutting and pasting some in one of his J2EE programs.

      If you've ever been looking at something in the language (not the library) and wished that it worked just like that, only different, that is one case where you use a macro.

      --
      t
    2. Re:LISP is amazing. by anactofgod · · Score: 5, Insightful

      I love it when people comment on Lisp without learning even most rudimentary aspects of the language. Not to single you out, but it is obvious to when one reads a comment posted by someone who is regurgitating commentary provided elsewhere by other who know nothing about the subject.

      I'm not certain what you've learned, but it certainly isn't "a lot". Certainly not about programming language design in general, and Lisp in particular. If you had even taken the time to read about just the history and design of Lisp, which is accessible to even the layman, you'd be able to post a more insightful comment than you just did. Why don't you try that, at minimum, since you are obviously uninterested and/or incapable of learning the technical apsects of the language.

      As for Lisp being an experimental language, nothing could be farther than the truth. Lisp is a language that was several decades ahead of its time in design, functionality and capability. Everything else is just now catching up. Evidence all the effort to fold in Lispy features into Python, Perl, Ruby, etc., etc. The thing is, these languages' designers are trying to bolt the features into their language after the fact. While Lisp Just Works.

      So, since you raised the topic, what's the answer? What would you have us "move on" to?

      --

      ---anactofgod---

      "Equal opportunity swindling - *that* is the true test of a sustainable democracy."
  2. Re:This is not a troll, but a query... by tenordave · · Score: 5, Insightful

    1) macros will blow your mind. Read Paul Grahams' 'On Lisp'
    2) takes bottom-up programming to the extreme. Really does help, but takes a while to get used to.
    3) Much better to develop in...interact with the interpreter, compile individual functions and run them, change variables in a running image...

    --
    http://students.washington.edu/djwatson
  3. Re:This is not a troll, but a query... by Neil+Blender · · Score: 5, Funny

    1. You can post on slashdot when ever the topic comes up.

    2. You can think of yourself as extra cool.

    3. It'll get you laid.

  4. Re:This is not a troll, but a query... by Lisper · · Score: 5, Insightful

    "Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot."

    - Eric Raymond, "How to Become a Hacker"

  5. practical? common? by daraf · · Score: 5, Funny

    (if (or (= lisp practical) (= lisp common)) (monkeys-fly-out 'my-ass) (life-as-normal))

  6. Re:This is not a troll, but a query... by ajs · · Score: 5, Interesting
    1) macros will blow your mind. Read Paul Grahams' 'On Lisp'
    2) takes bottom-up programming to the extreme. Really does help, but takes a while to get used to.
    3) Much better to develop in...interact with the interpreter, compile individual functions and run them, change variables in a running image...
    Of course, these things are true of most any functional language. IMHO, LISP is a poor choice as a starter language if you're looking for the above wins. I would start with Haskell or Scheme and move on to LISP once you had your bearings.

    Common LISP is a very old language (not as old as LISP, of course), full of the same kinds of pitfalls that any language its age or older shows (e.g. C, FORTRAN, etc). It is best to start with younger languages and work your way back.
  7. Best Lisp Book: On Lisp by ari_j · · Score: 5, Informative

    Paul Graham's book, On Lisp, is the single best book on programming I have ever read. You can get it as a PDF from his website, for free.

    You will also want to read his essay, Revenge of the Nerds, for some serious insight into why Lisp is just so darn good.

    If you're just starting on Lisp, the best place to start is with GNU CLISP, although you will find yourself wanting to use Emacs with SLIME to interact with your Common Lisp environment. I use SBCL, but CMUCL and CLISP are also acceptable. On my Powerbook, I use SLIME with OpenMCL.

  8. Common Lisp and Schem are really different. by notany · · Score: 5, Funny

    Comon Lisp and Scheme are as different as programming languages can be.

    Scheme can be said to be ontological attack against Lisp. It looks Lisp but is as far from Lispiness as you can and being still Lisplike.

    Schemer: "Buddha is small, clean, and serious."
    Lispnik: "Buddha is big, has hairy armpits, and laughs."
    -- Nikodemus

    Greenspun's Tenth Rule of Programming:
    "Any sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp."

    Common Lisp people seem to behave in a way that is akin to the Borg: they study the various new things that people do with interest and then find that it was eminently doable in Common Lisp all along and that they can use these new techniques if they think they need them.
    -- Erik Nagggum

    More than anything else, I think it is the ability of Lisp programs to manipulate Lisp expressions that sets Lisp apart. And so no one who has not written a lot of macros is really in a position to compare Lisp to other languages. When I hear people complain about Lisp's parentheses, it sounds to my ears like someone saying:

    "I tried one of those bananas, which you say are so delicious.
    The white part was ok, but the yellow part was very tough and tasted awful."
    -- Paul Graham

    Lisp is about rising above implementation to saying something of lasting
    value. -- Kent Pitman

    Pascal is for building pyramids -- imposing, breathtaking, static structures
    built by armies pushing heavy blocks into place. Lisp is for building
    organisms -- imposing, breathtaking, dynamic structures built by squads
    fitting fluctuating myriads of simpler organisms into place.
    - Alan J. Perils

    Puns are pricey to have in the language becuase they lead to ambiguity
    but they are also a source of great expressional power, so we live
    withthem. People who don't like them should probably seek out Scheme,
    which tends to eschew puns, for better or worse.
    -- Kent M Pitman @ comp.lang.lisp

    Q: How can you tell when you've reached Lisp Enlightenment?
    A: The parentheses disappear.
    LISP has survived for 21 years because it is an approximate local
    optimum in the space of programming languages.
    -- John McCarthy (1980)

    ``Lisp has jokingly been called "the most intelligent way to misuse a
    computer". I think that description is a great compliment because it
    transmits the full flavor of liberation: it has assisted a number of our
    most gifted fellow humans in thinking previously impossible thoughts.''
    -- "The Humble Programmer", E. Dijkstra, CACM, vol. 15, n. 10, 1972

    Lisp is like a ball of mud--you can throw anything you want into it, and
    it's still Lisp".

    Java was, as Gosling says in the first Java white paper,
    designed for average programmers. It's a perfectly
    legitimate goal to design a language for average
    programmers. (Or for that matter for small children, like
    Logo.) But is is also a legitimate, and very different, goal
    to design a language for good programmers.
    -- Paul Graham

    > The continuing holier-than-thou attitude the average lisp programmer...

    There are no average Lisp programmers. We are the Priesthood. Offerings
    of incense or cash will do.

    -- Kenny Tilton at c.l.l

    Dalinian: Lisp. Java. Which one sounds sexier?
    RevAaron: Definitely Lisp. Lisp conjures up images of hippy coders,
    drugs, sex, and rock & roll. Late nights at Berkeley, coding in Lisp
    fueled by LSD. Java evokes a vision of a stereotypical nerd, with no
    life or social skills.

    In the Algol family, parentehses
    signal pain. In the Lisp family, they signal comfort. Since most people are
    highly emotional believers, even programmers, it is very hard for them to
    relinquish their beliefs in their associations of parentheses with pain and
    suffering. This has nothing to do with aesthetics, design rationales, ease
    of u

    --
    Dyslexics have more fnu.
  9. Re:This is not a troll, but a query... by smug_lisp_weenie · · Score: 5, Insightful

    There is really only one thing you need to know about lisp- Lisp essentially has NO SYNTAX. What this means is that your program is an abstract syntax tree that goes directly into the compiler.

    Compilers in other languages first need to convert the program into an AST before compiling the code. (this is a bit of an oversimplification, but essentially true.) If you want three reasons, I can explain the repercussions of programming directly in an AST:

    Elegance: In Lisp, you don't have to worry about idiosyncracies in the head of the language designers like you do in other languages: You don't have to worry about whether AND has precedence over EQUALS (Delphi programmers know this trap) you don't need to worry when a line needs to end in a semicolon, etc. etc.

    Macros: By being an AST, Lisp lets you trick the compiler into thinking it sees other code than is actually there. This is COMPLETELY DIFFERENT than so-called "macros" in other languages- In Lisp you can turn your programming language into basically ANY programming language you want, within the language itself. Read Peter's excellent book or check out this site for more info.

    Productivity: You can program in the purely-functional style that has been shown to increase programmer productivity by having a property called "referential transparency" and having the easily serializable syntax-expression format. Basically, with Lisp you can analyze/manipulate/automate the bejeezus out of your code very easily, under the mantra "code is data, data is code".

    That's what I like about Lisp, anyway...

  10. Re:My first exposure to list ( and a mirror of boo by omnirealm · · Score: 5, Funny

    Whenever I think of Lisp, I'm transported back in time to 1975 where I'm trying (unsuccessfully) to learn this as my 2nd programming language after Fortran IV (on a DECsystem-10, no less).

    I've heard it said that someone just learning how to program can pick up Lisp in a day. If you happen to already know Fortran, it will take two days.

    --
    An unjust law is no law at all. - St. Augustine