February 03, 2004
Reading Code, Idiomatic Lisp
Brian Marick learned something new about how Richard Gabriel reads code. Patrick Logan has a schemey take.
I definitely read code in a Gabrielesque style as opposed to the Marick approach.
- Look for a key name.
- Quickly skip down to the code of maximum density. That's the important code. If that's not clear, find the declarations that clarify it by scanning upward. The most important ones will be nearby.
Using an &optional parameter as an internal, local variable? Jim Firby taught me to avoid that when I first learned lisp.
Posted by jjwiseman at February 03, 2004 09:41 AM
Well, the optional parameter isn't really an internal, local variable. It's a parameter for the tail-recursive call to the function. Making an optional argument for an accumulator just saves you the use of the labels for very simple tail-recursion. Doesn't seem like a sin to me, just a way of handling a boundary condition.
Now, using an optional parameter as a real internal, local variable is a sin, of course. But that isn't this case.
I wonder to what extent I'm comfortable with this case because I've also written a bunch of Prolog, which is much more strictly recursive than Lisp...
Also, there used to be good reasons of optimality to avoid labels in many CL implementations. Allegro either didn't tail-call optimize labels expressions properly, or didn't know that they did tail-call optimize them correctly (my correspondence with them never clearly answered whether this was a problem they fixed, or had never been a problem, although they had said it was....).
And, of course, some people just hate labels and like to have lots of top-level defuns instead.
I've never acquired real LISP (or Scheme) reading skills...I work my way through what I can. Makes more sense to write than to read.
LISP just doesn't have enough signposts. Stuff needs to stick out; whitespace and punctuation, things like that. We love our parentheses; they do what we need, they do everything. They do too much.
I don't want to have to internalize/comprehend a multi-character symbol to get code. I want to be able to get code by the _shape_ of the thing.
re vars in param list: Depends on whether you think a param list is an api... I tend to think it's somewhat of a burden to the user to clutter up the param list with all sorts of dirt. But maybe that's my antiseptic Javamind thinking.
re labels: I hate all those things that require too many damn parens. let/cond/labels/flet. Here I agree with Paul Graham in that speech he has at technetcast.
re reading: People don't spend enough damn time indenting their code. Norvig's code where he puts two params per line on a function call, is just plain funky. In a bad way.
Reading Ross Jordan's comment, I was led to wonder: how many of you actually /read/ lisp code as opposed to debugging it? As I think of it, it's pretty rare for me to read a Lisp program for any purpose other than to debug it, modify it, or figure out why some function call barfed (i.e., dope out the parameter list of a function).
Other than that, I don't think I agree --- Lisp has plenty of signposts. Look at DEFPACKAGE forms. Read documentation strings and comments. Use LOOP. Declare stuff. Bind variables tightly around the context where they're used, etc. Let emacs work its whitespace wizardry!
I debug hunks of Lisp, perl, and odd bits of other languages. In my experience, Lisp is at least as easy as the others....
As far as Tayssir is concerned, I don't see how you can have it both ways: if you want parameter lists to be APIs, you ought to be happy to have stuff like LABELS, FLET, etc. that keep non-api function signatures from messing up the namespace.
And I *love* LET. I hate having to read Lisp code where someone makes like a C programmer and just LET-binds everything up top (or worse, uses &AUX), and then SETFs them later on. It's a pain in the neck to tell if a variable's value is meaningful at any point in the program if you do that. To the maximum extent possible, I like to have a variable's lexical extent map exactly onto its semantic extent. If I'm done with a variable, I want it to not be there --- its LET block should close and it should be GONE.
No, I simply wish there were less parens involved. I like the idea of them.
Not that I prefer Scheme, but I like the nested defines more. Admittedly I'm just venting and perhaps there's a precise argument that shows I'm off my rocker.