An Ode To LOOP
A Hidden Lesson in Lisp Style
LOOP: the venerable iteration construct in Common Lisp. Much maligned, much loved, and much to teach. A short post.
Thou still unresting ox of programming Thou working dog of Lispers who control Pithy key phrases that make expressing Iterations diverse so much less dull What brain-mad coder taunts about thy faults of extension or learning, or of both, on Reddit or the sloughs of Planet Lisp? What noobs or frauds are these? Why do they loathe? What argument might prompt their swifter halt? Can I convince with 'passioned words so crisp?
With apologies to the ghost of Keats
A LOOP EXPRESSION
Consider the following
LOOP expression, and keep this example in mind as you peruse the rest of this post.
(loop for name being the hash-key of person-table for person being the hash-value of person-table for iterations from 0 when (string-equal name "larry") collecting person into larrys and do (format t "Hi, I'm ~a~%" (full-name person)) when (string-equal name "darryl") counting name into darryls-count while (< darryls-count 1000) finally (return (values larrys darryls-count iterations)))
Just reading it, do you have an idea about what it is doing?
It seems to be looping over a hash table and doing the following things:
- Keeping a running total of the number of
collectinga list of persons named
"larry"and storing it in variable called
- Additionally, for each such Larry, print their full name.
countingthe number of people named
"darryl"that occur, and storing that count as
- But only doing all of the above so long as we've seen fewer than 1000 Darryls.
finally, we return several values, the list of Larrys, the number of Darryls, and the total number of interations.
LOOP has some defects, some boons, and some lessons to teach.
LOOP sucks because of ...
- Extensibility: it cannot be used to iterate over exotic data containers. Just ranges, lists (in two ways), vectors, and hash tables.
- Lispiness: it doesn't look like the rest of Common Lisp. Note the relative lack of parentheses in the above!
- Superfluity: it is an entire extra language unto itself, with hard-to-recall keywords and syntax. E.g.
being the hash-key of ....
LOOP is great because of ...
- Versatility: Even though it isn't extensible, it is still pretty darn versatile. With
minimize; you run code
untilsome condition is true; you can check that a condition is
nevertrue, or that
thereisat least one true instance of the condition; you can define local variables, pattern match on binding forms, and iterate over most built-in data structures; and on and on...
- Readability: Despite feeling odd,
LOOPexpressions are fairly descriptive of what they're doing. If you have even a passing familiarity with programming, then you can probably figure out what the above does. It reads almost like psuedocode.
- Performance: Iterating with
LOOPis frequently quite fast. Expressions expand into highly imperative code that uses
SETQ. In other words, the extra language is worth the trouble to learn because it generates fast code with less typing. The above expression, for example, expands into roughly 70 lines of lower-level Lisp.
LOOP is typical of Common Lisp style as a whole. By "style" I do not mean what code looks like in your editor. Instead, by "style" I mean the way that Lispers approach problem solving, and the way that Lispers approach Lisp itself.
LOOP has lessons to teach about Lisp Style:
- Just to prove how good Lisp is for defining DSLs, one is included in the standard! From this I learned that sometimes a new language makes some domains easier to work in.
LOOP's limitations motivated many Lispers to extend the language, a very Lispy practice indeed. From this I learned that it is totally appropriate to extend Lisp to meet my needs.
LOOPprovides further evidence that Lisp is a truly multi-paradigm technology, one that that embraces practicality. That is,
LOOPmay stand out, it may seem impure, but it is a practical tool for implementing loops. From this I learned to stop worrying about purity in favor of doing what works.
LOOP may not be extensible, but Lisp sure is. Try one of iterate, for, or series if you need to loop over exotic containers.
LOOP syntax may not be immediately obvious, but there are loads of great resources for learning to
Keep on hacking!