I got through the first four chapters of PAIP yesterday and today. It's good so far. I had reservations about spending $80 on a book, but it's 950 pages and almost all of it is good stuff, from what I can see at a glance. Little space is wasted on introduction material or tutorials for people who know nothing about programming. He dives right into the good stuff in chapter four.
Already I've picked up a few nice bits of info, interesting standard functions / macros like
TRACE which is good for debugging. And
SUBLIS which takes a list of (key . value) sublists and replaces all the keys with all the values, in some other list. Common Lisp is such a freaking huge language, in terms of its standard library of functions. Good thing or bad thing? It may be a bad thing if not for the fact that you load Lisp once and it persists forever.
Norvig makes an interesting point about the REPL. What do most programs need to do? Take input from the user, do something with it, and give output back to the user.
To get input, your program can read from command-line args, or prompt to STDIN, or take it out of text fields in a QT app, or read it from a config file. But it's generally always strings. So you get some strings, and then what? You have to figure out what the strings say, and either turn the strings into something usable or use the strings to figure out what action to perform. So you may have a dedicated library to parse command-line args and a dispatch table to map them to function calls. Or you may match the strings against a regex and depending what the strings look like, turn them into your language's representation of an integer or float using some "parseInt" or "parseFloat" functions. Or if your strings are XML, you may parse them into some big funky XML structure, then access bits of that structure to figure out what to do.
In Lisp on the other hand, you happen already to have a powerful reader/parser at your disposal: the REPL itself. It already knows how to read string representations of lists, numbers, pathnames, and many other things, and it can turn them into Lisp objects for you with no effort on your part. If you were using Ruby or Perl, short of
eval, you wouldn't get anything close to that capability in your program.
What's more, the REPL knows how to read string representations of Lisp code (new functions and function calls etc.), and evaluate the code and end up with Lisp objects. It would be like if you wrote a C program which prompted you for input, and the input you gave could be a string representing a new C program that when run would produce a string that contained your input (or produce in-memory C structures your C program could use). So the main program would call GCC and compile and run your input to get results and use those results as its final input. Except that still wouldn't be nearly as powerful as what Lisp is doing.
So if you can figure out how to shape your input into a form that the Lisp reader can read, you're set. And it so happens sexps are a great representation for a great many things. Maybe this is part of why Lispers seem to worship the REPL and shun compiling their apps into command-line, standalone executables? Maybe this is part of what's meant by the oft-quoted-to-death Greenspun's 10th Rule?
Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.
Much more PAIP to follow. It should be enjoyable. There's nothing like a good book.