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

42 of 617 comments (clear)

  1. My first exposure to list ( and a mirror of book ) by winkydink · · Score: 3, Informative

    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 never revisited Lisp. Perhaps now that I have the book, I'll give it a shot.

    You can download a copy here if the main site is too busy.
    ~

    --

    "I'd rather be a lightning rod than a seismometer." -Ken Kesey

  2. Re:LISP is amazing. by Homonymous+Howard · · Score: 3, Informative
    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.
    Common Lisp has first and rest as accessors for lists. Many Lispers consider it good style to use them when treating conses as lists and to use car/cdr when treating conses as binary trees.
  3. Re:Good book, questionable language. by tenordave · · Score: 2, Informative

    Where the hell have you been? It has better exception handling than most langauges (including java, read the book), and was one of the first languages to use garbage collection. In addition, you'll find all the normal data structures in all the other languages, threading, and so on that you're used to. CL of today is not CL of the past.

    --
    http://students.washington.edu/djwatson
  4. C++/Java/LISP Side by Side Comparison? by Anonymous Coward · · Score: 2, Informative

    Lately there has been a lot of LISP hype mostly thanks to Paul Graham. I keep hearing "Macros are amazing", "totally different way of thinking about programming".

    That's great and all but I can't find any concrete examples. I want to see a list of problems that are either difficult or nearly impossible with Java/C++ and see LISP's implementation.

    Can anyone help me to get past the hype?

    1. Re:C++/Java/LISP Side by Side Comparison? by Anonymous Coward · · Score: 2, Informative

      Here's one:

      Add a construct to your language called "with_open_file" that takes three arguments: a filename, a variable name, and a block of code. The construct should open the file, store the open file handle in the variable, and then run the block of code with that variable in its scope. After the code completes or has an exception, the file should be safely closed. Example:

      with_open_file("/tmp/flozz", f) {
      f.write("Hello, world\n");
      if (rand() > 0.5)
      throw Exception;
      }

      Yes I know how to do exception handling and so forth in Java/C++ but I want you to add a *new keyword* to your language.

      Another one:

      We're working on a timing-sensitive project. I need to you to add another keyword to your language. This one is called "sleep_between" and should take an integer argument N and a block of code. It should insert "sleep(N)" statements between each statement of the code and then run it. For extra credit, create a general keyword that inserts ANY block of code between the statements of another block of code, and use that to implement "sleep_between". Example:

      sleep_between(1) {
      print("3");
      print("2");
      print("1");
      print("contact");
      }

      Extra credit: modify your code so that it also inserts the sleep() calls at the end of every *loop* within the block. So if I rewrote my example to say "for n = 3 downto 1 print(n)", it would still sleep between each statement.

      Another one:

      The junior programmer didn't know about the "with_open_file" statement. His code keeps throwing exceptions and leaving data unsaved. We're shipping tomorrow and we need to have this fixed this afternoon. Write a function that runs his code and rewrites it on the fly to use our safe "with_open_file" keyword. (In Lisp this is *easier* than just doing a search and replace, btw).

  5. Re:LISP is amazing. by haystor · · Score: 2, Informative

    If you are a python programmer, there is nothing LISP can do that python can't.

    Full blown macros are still beyond the reach of python I believe. I use these all the time and any language without LISP macros feels like I'm back in high school doing endless exercises over things I already know. Other languages talk about patterns and abstraction but their idea of this pales next to what can be done in LISP.

    I'd elaborate but people attached to their own languages won't believe.

    --
    t
  6. Re:This is not a troll, but a query... by Anonymous Coward · · Score: 3, Informative

    1. Run-time typed, like Python, with optional compile-time declarations to improve efficiency in cases where compiler can not predict types.

    Advantage is much fast code creation, with run-time safety, and option to get efficiency later.

    2. Well thought out data structures with nice language support.

    For example, ability to inline arrays and lists and symbols very conveniently in code. Ability to read complicated data structures (data files) without writing parsers, that are easier for humans to interpret and write than XML.

    3. Ability to run code during compile process.

    Enables very fancy compilation strategies, such as turning data structures into compiled code conveniently. Allows efficient, tailored extension languages to be written quickly.

    In general, Common Lisp has many features that enable big, interesting programs to be written very, very quickly.

    It has many downsides too, primarily the fact that the language spec predates many modern concepts such as concurrent threading and TCPIP. Interaction with other languages is mediocre - most implementations can call system libraries easily, but calling Common Lisp code from other languages is typically quite difficult. CL programs are rarely used as libraries by other languages.

  7. Re:My first exposure to list ( and a mirror of boo by ajs · · Score: 3, Informative

    If you find LISP interesting, Haskell might also be of interest.

    Recent interest in Haskell has exploded because of the implementation of Pugs in GHC. Pugs is a compiler / interpreter prototype for Perl 6, which is also a functional language, borrowing many concepts from LISP and smalltalk (as well as just about every other popular research or practical programming language).

  8. Re:This is not a troll, but a query... by Anonymous Coward · · Score: 1, Informative

    > Lisp implements everything as a binary tree.

    Along with arrays, strings, hash tables, classes, and any data structure you can think of. "Lisp only supports lists" is a myth, even the first dialects in the 60's had other data types.

    > None of these features give it any advantages over Python, Java, or a host of other newer languages.

    Lisp has better reflection, exception handling and more expressive power than any of these languages. Python especially is a sad joke -- it is hundreds of times slower than good Lisp implementations.

  9. Re:Learn Lisp Without Installing Anything on Your by smug_lisp_weenie · · Score: 3, Informative

    Oops- Here's the link: tutorial

  10. 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.

    1. Re:Best Lisp Book: On Lisp by Tayssir+John+Gabbour · · Score: 2, Informative
      While LISP is a cool language, I really like what I've seen of the strongly static-typed functional languages like the ML family (especially OCaml.) I love the pattern matching features for example. The only thing I miss in them is the macro mechanism from LISP
      Qi (which is built on Common Lisp) is touted as having "the most powerful type system of any existing functional language, including ML and Haskell." Perhaps you may wish to try it out and see.
  11. Re:This is not a troll, but a query... by tchernobog · · Score: 2, Informative

    I can just say what it helped for me, so it's subjective, but:

    1. Opened my eyes on how recursion should really be used, and improved my software design abilities a lot, since you're encouraged on writing new small functions and then put pieces together. LISP is built on LISP, and I found it a really educative language (and that's the same reason because I dislike Java, with its too-easy-to-become spaghetti-code). Moreover, in LISP it isn't just that a program has to work; it has to do it in an elegant way.

    2. It is both a functional and object oriented programming language. Along with SmallTalk, in the '80 it revolutionized the programming language zoo, and some damn big programs started using it as an extension language (Autocad comes to mind). It has left me surprised studying it how much newer languages take from LISP, even something like Java.

    3. It is a really high level language! A lot of libraries is already ready to use. Although the learning curve is really slow at first, LISP repays you a lot of your effort. Unfortunately there aren't many books on the subject. I really welcome this book, and I'll read it asap. Me, I've learned it using the wonderful Graham's book.

    I also noted that in LISP finally you can "test code as you write", as they teach you in CS courses, but tight schedules and other languages often make that difficult in a real world scenario.
    And in a hundred of lines you can write your own ray-tracer (see always Graham's book). :-)

    Ah:
    4. Extend GNU Emacs. That's the "c00l" factor that makes you geeky, at least for me. ;-)

    --
    42.
  12. Re:This is not a troll, but a query... by joto · · Score: 2, Informative
    Could someone proficient in LISP give me three cogent reasons to learn the language?

    Try here

  13. Re:This is not a troll, but a query... by fizbin · · Score: 2, Informative

    While I'm definitely a ruby fan, the ability to easily write self-modifying code (and by that I assume you include the ability to easily write code generators and to mix and match those code generators with the rest of your code - aka common lisp macros) is really something rather unique to lisp. You don't think that this provides a compelling reason to learn lisp? I admit, that's only one reason, but it's a big one.

    I've written Perl code that generates more Perl code that is then fed to eval. I've helped people write python code that generates more python code, and that is truly painful (the indentation-based grouping of Python makes this much more difficult than it needs to be). I admit I haven't done that specifically in Ruby, but I can't imagine that the experience would be very different from the same exercise in Perl.

    None of these come close to the power and ease of use of Common Lisp macros.

    I also question your statement "Lisp implements everything as a binary tree.". While it is true that the cons pair is the most common lisp data structure, and that all code is seen in terms of cons pairs, it's disingenuous to say that Common Lisp doesn't have arrays (vectors), hashtables, or structures with named slots. Often times people will produce a benchmark showing that "lisp is slow", when in fact they've gone and compared lists in lisp (implemented essentially as singly linked lists) to lists implemented with arrays in some other language, or compared assoc. lists with hashtables.

  14. Re:This is not a troll, but a query... by Tayssir+John+Gabbour · · Score: 3, Informative
    Could someone proficient in LISP give me three cogent reasons to learn the language?
    Bacon-and-eggs things to help you write more robust code:

    • Powerful basic datatypes. Multidimensional extensible arrays with fill pointers. One-way/two-way/synonym streams, strings with fill-pointers, integer/rational/complex/floating-point/big/fixnum numbers, bit vectors, OOP with metaobject-protocol/{before/after/around}-methods/ multiple-inheritance/multiple-dispatch, errors/warnings/conditions. Etc.
    • Something like XML, but much more readable, built into the language. So you can perform data-directed programming without switching to XML. And unlike XML, Lisp's sexps support more than just plain text.
    • The "Conditions System", which among other things offers something far more powerful than exceptions for error-handling. Imagine exceptions that don't have to just burn up the stack.
    For the moment, let's forget pretty stuff like macros.
  15. Re:My first exposure to list ( and a mirror of boo by behindthewall · · Score: 2, Informative

    FYI, the download-able files contain the book examples' source code. They do not contain the book itself.

  16. That's not what car and cdr are for... by jtdubs · · Score: 4, Informative

    That's probably not the right way to think about it. A cons cell is a data structure that holds a pair of items. The first is the car; the second is the cdr. The accessors for those parts of a cons cell also have the names car and cdr.

    Linked lists are just one data structure that you can implement with cons cells. You can also implement a stack, queue, binary-tree, association-list, etc...

    If your are using "cons cells" in your program, use car and cdr.
    If you are using lists that are implemented via cons cells use first and rest.
    If you are using a stack use push and pop.
    And so on...

    In other words:

    CL-USER> (car (cons 1 2))
    1
    CL-USER> (cdr (cons 1 2))
    2
    CL-USER> (first (list 1 2 3))
    1
    CL-USER> (rest (list 1 2 3))
    (2 3)

    Justin Dubs

  17. Re:LISP is amazing. by dragondestroyer · · Score: 2, Informative

    There are FIRST ... TENTH and REST. See http://www-2.cs.cmu.edu/Groups/AI/html/cltl/clm/no de149.html

  18. Re:LISP is amazing. by sketerpot · · Score: 3, Informative
    It's much easier to use than assembly. In assembly language, for example, it would be non-trivial to do something like this:

    (remove-if-not #'oddp list-of-numbers)

    That returns a list of all odd numbers in a list of numbers. With this sort of a difference in ease of use, why are you comparing Lisp to assembly language? My guess is that you're just talking out your ass.

  19. Re:How about OS interaction by dragondestroyer · · Score: 2, Informative

    This website may help http://www.podval.org/~sds/clisp/impnotes/syscalls .html, but be careful as it is not always completely clear which functions work on which platforms.

  20. Re:Lisp Scheme by joto · · Score: 2, Informative
    Let's be accurate. Common LISP is to Scheme as C++ is to, perhaps, C - both dialects of the same basic language, but one far more feature-rich that the other

    No. This is false. And it doesn't really matter that you or many other people believe it to be true. It's still false.

    Scheme is a block-structured language modeled on Algol. Common Lisp is a natural evolution of LISP 1.5. As part of the evolution, sure, some features from Scheme have been sneaked back into Common Lisp, but they are really very different languages.

    LISP is to Scheme as BASIC is to Microsoft BASIC. One is a dialect of the other.

    No, it isn't. Scheme and Common Lisp are no more dialects than Pascal or C++ is. And I really mean what I say. C++ is an evolution of C, which itself is an evolution of B. Something similar can be said of Common Lisp.

    Pascal is an ivory-tower language written to prove a point, that later, with various extensions, almost got useful, and were actually used for real programming. Something similar can be said of Scheme.

    And they are certainly not dialects. They are far too different.

    Scheme has tons in common with Common LISP.

    Pascal also has tons in common with C++. I.e. they are both block-structured imperative languages.

    Sure Scheme has tons in common with Common Lisp. But there are also tons of differences, and many of these differences are important! Such as scheme being block-structered, and Common Lisp not being block-structured.

    If you try to look a bit further than superficial syntactic issues, you will find that the languages are quite different.

    It's the same story as with Java and Javascript. People without a clue believe them to be similar. People with a clue know they aren't.

  21. Re:This is not a troll, but a query... by anactofgod · · Score: 2, Informative

    I am an ex-Lisper who strayed from the One True Language and am now in the process of regaining proficiency to rejoin the Lisp Priesthood. My motivation is that I am tired of the limitations I hit due to the deficiencies inherent in all the other supposed "modern" popular programming languages I've encountered. I also remembered really *enjoying* the whole process of rolling Lisp code, a joy I lost long ago when I strayed into the mass market of more socially acceptable programming languages.

    The deficiencies of modern languages I speak of above are not necessarily those of capability (though those exist), but are primarily of language design. Most languages are designed with the goal of increasing the productivity of the average programmer. Lisp's design was entirely about elegance, simplicity and power. I can give you lots of reasons why Lisp is better than insert-your-favorite-programming-language-here, but that will just devolve the conversation into a jihad. So, let me tell you what Lisp is fantastic at.

    Actually, you know what? I'm not going to reiterate that which others have stated. If you really are interested, let me just point you to a couple of sites to get you started on your journey of discovery. Read Paul Graham's essays/articles, the first two chapters of Peter Siebel's book available on-line, this essay on Lisp's prowess as a rapid prototyping language and this paper on why the future of the (semantic) Web may lie with Lisp. Then, if you appetite is whetted, Google for more info, download a flavor of Common Lisp, work thru Seibel's book, and experience it for yourself.

    Or not. If you're perfectly satisfied with whatever flavor you how you do your work, there is absolutely no reason to learn ANYTHING new, is there?

    Learning Lisp. It will take you back to the future.

    --

    ---anactofgod---

    "Equal opportunity swindling - *that* is the true test of a sustainable democracy."
  22. Re:Good book, questionable language. by Ulrich+Hobelmann · · Score: 2, Informative

    You are clueless.

    Common Lisp is lexically scoped, in fact it has closures (unlike Java). 1984 it was standardized with a really powerful CLOS (CL object system), in comparison to the puny Java object system 10 years later.

    Lisp also *invented* garbage collection! Without it you'd still be using FORTRAN, not Java.

    And the AI comment is simply stupid. Any language can be used to do AI; Lisp is simply used for it, because it's way more powerful than Java and other crap.

  23. Comment removed by account_deleted · · Score: 2, Informative

    Comment removed based on user account deletion

  24. Re:This is not a troll, but a query... by Anonymous Coward · · Score: 1, Informative

    Common LISP is a very old language

    Common Lisp (!) was created by amalgamating several other variations of LISP into an ANSI standard that was ratified in 1994.

    Considering most C code out there now is on the ANSI C 1989 revision I don't see how this argument flies.

    CL has also had support for imperative, functional, and OO programming since it's creation. (You can use any one of the programmin methods (or all of them). CL doesn't impose a paradigm on you -- you choose whichever one you want.)

    Throw in handling of complex number (1+2i) and highly accurate math (20/30 results in a return value of 2/3, not 0.66666...7) and you now can now see why many people like it.

  25. 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
  26. Re:LISP is amazing. by e40 · · Score: 2, Informative

    OK, then do it. (defmacro left (x) `(car ,x)) and (defmacro right (x) `(cdr ,x)).

  27. Re:An ideal world would run on LISP... by noahm · · Score: 3, Informative
    Two years ago, I saw a practical demonstration of a Symbolics LISP Machine from 1987

    The frightening thing is, lispms from the 80's enjoy quite some popularity among certain people where I work. They really are amazing machines, and those who use them regularly feel strongly that there hasn't been a more usable environment in all the time since they were created.

    Let me tell you, though, as a sysadmin, these things can be a royal PITA. Not because there's anything wrong with them (well, except maybe for their complete lack of security) but they're just so different.

    There are still many copies of The Lisp Machine Manual lying around, including an early rant by RMS against the recent trend of software hoarding. It makes for an interesting read...

    noah

  28. Re:This is not a troll, but a query... by fizbin · · Score: 3, Informative
    No, that's not what I'm asking for; although I will admit that I like Ruby's ability to pass a following code block into any function, this is really something completely different. (For non-rubyers: the poster is talking about a facility that's similar to being able to pass an anonymous function as an argument with nice, clean syntax that doesn't get in your way - similar to the way that the perl builtin sort and map functions let you pass in a block)

    A macro basically allows you to rewrite code completely, reaching into the bowels (if necessary) to rip out and mangle what needs to be done.

    A basic example is the setf macro. This macro is used for basic assignments:
    (setf captain "Picard")
    (setf answer (+ 23 42))
    Except, of course, that the first argument can be more than just a simple symbol:
    (setf (aref array 0 10) new-value)
    (setf (car mypair) mynewcar)
    So far... so what, right? After all, this "fancy" syntax is just equivalent to the java code:
    array[0][10] = new_value;
    mypair.car = mynewcar;
    Okay, but how about this - suppose I define some functions dealing with a simple berkeley-style database. Say, (get-from-db dbref keyvalue) and (set-to-db dbref keyvalue newvalue). Now, if I set things up properly, I can make setf work with these functions too, so that the user can do:
    (setf myprevval (get-from-db id key))
    ; some calculations on the previous value here
    ; do some other stuff here
    ; some calculations to get the new value
    (setf (get-from-db id key) newvalue)
    See how I never explicitly call my database setting function? The last line there never actually calls my get-from-db function - instead, it reaches into the parentheses and rewrites the code so that what happens is a call to set-to-db.

    That is, the user never has to know about the set function. Essentially, setf means "here, in the code, where I've said setf, instead go ahead and use whatever the appropriate setter function is for a reference of this type". (when I defined my db functions, I would have to call some macros to tell setf about get-from-db and set-to-db)

    Now, for this specific case - creating a unifrom set syntax for any "get"-type function you wish - Ruby has specific explicit syntax support. (just name the "set" method the same as the "get" method but add an "=" to the end of the name) Lisp, however, handles setf through the more general macro mechanism. This means that it can be extended in a bunch of different ways. For example, Lisp defines incf to mean roughly what C's "++" operator does, except again without special language support. (And incf will automaticaly take advantage of the setup I've already done for setf)

    In order to do its magic, setf has to be able to access the reference (get-from-db id newval) exactly as I typed it, and has to be able to rip apart and inspect the innards. This is something only a macro can do.
  29. Re:My first exposure to list ( and a mirror of boo by Anonymous Coward · · Score: 2, Informative

    Haskell has significant whitespace,

    Optional significant whitespace, but everyone uses it. IM(anonymous)O it works a lot better in a functional language than imperitive.

    Haskell syntax is really amazingly beautiful. Usually. Even if you don't find Lisp interesting, have look at Haskell.

  30. Re:My first exposure to list ( and a mirror of boo by Anonymous Coward · · Score: 2, Informative

    Wrong. The entire text of the book is on-line.

  31. Re:Libraries... by circusboy · · Score: 2, Informative

    this is a good set to start with, and look up asdf and asdf install for further libraries that are cross platform/implementation for lisp. saves a lot of trouble, and evens out the differences between the various lithpssssssss

    --
    -- it's ridiculous how many people misspell ridiculous... (damn, damn, damn...)
  32. Re:My first exposure to list ( and a mirror of boo by Myolp · · Score: 2, Informative

    I had a similar experience with Common Lisp a couple of years ago. Fortunately I found Scheme, which made the whole functional programming paradigm a whole lot more enjoyable.

    http://www.plt-scheme.org/

  33. Re:Practical Lisp? by Anonymous Coward · · Score: 1, Informative
  34. Re:LISP is amazing. by stesch · · Score: 2, Informative

    See What's with All the Parentheses? and the conclusion In other words, the people who have actually used Lisp over the past 45 years have liked the syntax and have found that it makes the language more powerful.

  35. Re:Libraries... by Anonymous Coward · · Score: 1, Informative

    There are many different Common Lisp implementations around, each having a different foreign function interface. This makes it harder to develop and maintain interfaces to existing libraries since each must be ported to a number of CL implementations. (In Python, Perl, Ruby, etc. you have one implementation of the language and when you port your library to that you are done.)

    Regarding strangeness: Common Lisp has hertiage from different formerly used Lisp dialects. This explains why the function names and some concepts are so inconsistent. It you want a clean and consistent Lisp, look at Scheme. Scheme was designed from scratch with teaching/learning in mind. However it doesn't come with some of CLs cool features (such as a built-in compiler). In my personal opinion another Lisp dialect is the last thing the world needs. But that might just be me... :-)

  36. Re:My first exposure to list ( and a mirror of boo by ajs · · Score: 3, Informative

    First off, let me say that I'm new to Haskell, and learning it, Python and (as of last night) Fortress at the same time, so I'm far from an expert.

    "Lisp can generally be made faster than Haskell"

    Certainly, and I'm not saying Haskell makes a good language for day-to-day coding. I'm just saying that it's a good place to learn functional programming.

    "Haskell uses lazy evaluation. Lisp uses strict evaluation unless you explicitly ask for lazy evaluation."

    For those who do not understand this point, it's worth going into. In C, when you say:

    c = foo() + bar();

    you call functioan foo and bar, add their results, and store that result in c. In Haskell a similar construct would store in c the information required to call foo and bar at a later time when/if you needed the value of c, but of course, if you just add c to another value, you just create a more complex result, you still don't invoke foo or bar.

    This is a very powerful concept, but can also lead to surprising results if you are used to programming in non-lazy languages.

  37. Re:engineering tradeoffs by Anonymous Coward · · Score: 1, Informative

    Incremental compilation in the lisp sense has always been possible in Java, you're just slamming it because it's not done the same (learn how to use a classloader and maybe you'll understand.) Java's (existing now and always has) version of incremental compilation works quite well, beats the hell out of C#, and any language that compiles to jvm bytecode has the same capacity.

    REPL could be done in Java, but few people seem to care to; maybe because not everybody likes to develop in such an environment. It has nothing to do with Java's capabilities, nor indeed does it have anything to do with lisp as a language, but rather a development approach.

    And Java lacks macros because, well, c-style macros tend to blow goat and are bad from an object-oriented standpoint. Macros in the lisp sense seem like they would be difficult to add to Java, but I'm uncertain as to how they would affect OO-cleanness.

  38. Re:engineering tradeoffs by sketerpot · · Score: 3, Informative
    Okay, try to name (or point to an article online that names) something wrong (or suboptimal, etc.) with the Common Lisp implementation of scoping, naming, reflection and code generation. Seriously, I'm really interested. I'm not an expert on Common Lisp myself, and all I'd read suggested that Common Lisp was actually far superior to any other programming language re: reflection and code generation (and I'd never heard of any problems in the way it handles scoping or naming).

    CL has some problems with the Meta Object Protocol (MOP), which is used for reflection and to modify the object system. It's not standard, but it's supported by all major Lisp implementations---and they usually have small differences, most prominently what package they put it in. Is it in the MOP package? Or perhaps the SB-PCL package? In order to make portable code that uses the MOP, you need a compatibility layer like Closer or MOPP or CLIM-MOP.

    That said, once you have all the compatibility code in place you can do amazing things with the MOP. I co-wrote a graphical object inspector that made heavy use of Lisp's introspection abilities, and Pascal Costanza added Aspect-oriented programming to Common Lisp with AspectL.

  39. Re:How about OS interaction by cstacy · · Score: 2, Informative
    "clisp" is the name of one implementation of ANSI Common Lisp. There are many implementations of ANSI Common Lisp, and each of them has its own proprietary extensions. "clisp" is unusual in that it is an interpreter (rather than a compiler).

    If you're asking how to manipulate OS processes in Common Lisp in general, the answer is that it is not defined by the ANSI standard. (The reason for this is that each operating system has a different idea what a "process" is, what you can do with them and how you do it, some operating systems don't have processes at all, etc. Processes are beyond the scope of the ANSI standard.) So each implementation does it slightly differently. The leading commercial implementations, in particular, have all these kinds of facilities, and they are portable across operating systems (Mac, Unix, Windows). So if you write your program to those APIs, your program will run on all operating systems.

    If you really meant "clisp", and you want to use their proprietary interface for this, then refer to the documentation entitled, "Implementation Notes". These notes are not about the internals of how clisp is implemented, but rather about the implementation-specific extensions to the language. (That label on their documentation confused me!) These notes come with your clisp distribution.

    If that's not acceptable, because you didn't mean "clisp", or you really need portability not just across operating systems, but also across different vendors' implementations of Common Lisp, people have written libraries which give you portable APIs to things like process manipulation (and network sockets, multiprocessing, and so on).

    These kinds of libraries are much easier to write in Lisp than in other languages. However, I don't know where to get the particular portability library (process manipulation) that you are seeking. I wrote my own. Maybe they are harder to find because it's so easy for people to write their own, but then people don't want to publish them for free. (Or maybe most people are just not writing programs that do a lot of process manipulation. Or they're happy with the non-portability of their programs and consider whatever solution they're using to be "practical" enough.) Anyway, here are some links to places I'd recommend exploring. I don't know if they've got what you want burried in there or not.

    A third solution to your problem, and maybe this is what you're looking for, is that you can just make Unix (or other C-language compatible) calls yourself directly from Common Lisp. The portability library for this is UFFI, the "Universal Foreign Function Interface". You will have to write a function-prototype for the function that you want to call. There might be issues with Unix signals or something. Your code will run in pretty much any ANSI Common Lisp implementation, on any operating system. (The not-yet-identified-maybe-hypothetical portability library for doing process/pid manipulation would itself be written using UFFI library. Not sure if anyone bothered. Extensive libraries for things like SQL database access has been written using UFFI, also.)

    Not having a comprehensive one-stop shopping place for libraries and OS interfaces is one of the things lacking in Common Lisp. Java and Perl have done a somewhat better job in that area, so far.

    Some other good places to look around for libraries and solutions are:

  40. Re:Talking to the OS by be-fan · · Score: 2, Informative

    It depends on the compiler. Nearly all Lisp systems have what's called an FFI, to access native libraries. Interpreters like Clisp have the runtime intercept ffi calls, and call the shared library. Compilers that compile to native code just use whatever ABI is specified by the platform. The system just sees machine code, it has no idea whether that code comes from cmucl or gcc.

    --
    A deep unwavering belief is a sure sign you're missing something...