April 30, 2002
PAIP Retrospective

Chris Rathman's posting at Lambda the Ultimate reminded me of Peter Norvig's retrospective piece on his 1992 book, Paradigms of Artificial Intelligence Programming.

Norvig first looks at the state of Lisp now compared to 1997, and concludes that the situation has become somewhat bleak. I don't get too worried about the relative numbers of usenet postings for various languages (part of Norvig's measure of language popularity), but he does mention one thing that has concerned me for a while: There is no work being done toward evolving a new ANSI standard for lisp.

I'm not sure just how concerned I should be about that. It is true, after all, that people are adding new features to the language (Franz' hierarchical packages, e.g.). And there are still some facilities for which standardization might possibly be premature (such as multiprocessing). But I worry a little bit that there won't be enough energy in the lisp community to deal with a more formal standardization effort when the time is right.

Lisp has warts, like any language. And eight years (the ANSI standard came out in 1994) is a long time to live with those warts.

On the plus side, Lisp still stands out among other languages, for many reasons. Norvig points out that other languages (particularly Java) now offer some of the benefits that were previously unique to Lisp. I've found, however, that when the fingers hit the keyboard, Lisp still wins:

  • First-class functions. The syntax for Java's inner classes is so clumsy, I feel like a sucker every time I use one. And Python's lambda is just a cruel joke.
  • Interactive development. I haven't seen anything like the industrial-strength debuggers that most lisp environments have.
  • Syntax and macros. Lisp has a consistent syntax for everything, and that syntax makes it really easy to write macros. Either other language designers don't understand how helpful macros are, or they quail at the prospect of implementing them for non-sexp syntaxes. You'd think that the scripting languages, at least, would recognize the utility of macros for creating domain specific/little languages.
  • Error handling. Other languages have exceptions. But they don't have handler-bind or restart-case.

More generally, there is a huge advantage to using a language with 40 years of history (I know, I've gone on about this before): Almost everything in the language fits together well (in what Kent Pitman calls the language's ecology). I'm no language designer, but it's often easy for me to look at a language and see features that could have easily been made to work together, but don't.

(Norvig's extraction of the 52 most important lessons from PAIP is kind of fun, too.)

P.S. lemonodor is still only half-alive. I'm settled in my new apartment, but I still need to take care of my home high-speed internet needs.

Posted by jjwiseman at April 30, 2002 02:28 PM
Comments

Re Python's lambdas: How bout blocks in Smalltalk
and Ruby. I've heard one ex-Lisper say that they
feel better than lambdas for imperative code.

Also, how important are restartable exceptions?
There's a great discussion of them (relating
real-world use histories) in _The Design and
Evolution of C++_. What do you want to use them
for? What have you used them for?

Posted by: Eric on May 11, 2002 08:16 PM

I don't know much about Smalltalk blocks; I think they are equivalent to lisp lambdas, but with extremely convenient syntax, right?

I have used CL's rather rich exception framework, though.

handler-bind lets me decide at the time the exception happens, in the dynamic context that it happened in, how to handle the exception. I've used it to grab extra information about the call stack at the time the exception occurred.

Restarts I have found to be useful mostly for development and debugging. They're used in many lisp implementations, for example, to handle the case where you've mistyped the filename of the lisp file you want to load, or you typoed a variable name. Instead of having to stop, correct the error, reload and restart, you can often indicate that you want to skip loading the file, load another file, use the value of another variable just this once, or use the value of another variable from now on. It's reallly convenient, and all implemented with restarts.

I use restarts quite a bit in the form of continuable errors: instead of just raising an error, I can raise an error but also offer the choice of ignoring it in a sane way. For example, in the RAP robot task execution system I worked on, when an error occured while executing a task you were given the option of continuing as if the task had failed. And this didn't have to be a decision that the user made while interacting with a debugger through a prompt or a dialog box; code *above* the task execution system can use handler-bind to call the 'continue' restart if it wanted, without the user being involved, and importantly, without the task execution system having to know anything about it.

I have only skimmed _The Design and Evolution of C++_, sounds like it might be worth reading more closely.

Posted by: jjwiseman on May 15, 2002 05:28 PM
Post a comment
Name:


Email Address:


URL:




Unless you answer this question, your comment will be classified as spam and will not be posted.
(I'll give you a hint: the answer is “lisp”.)

Comments:


Remember info?