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.
An Ode
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
iterations
so far. collecting
a list of persons named"larry"
and storing it in variable calledlarrys
.- Additionally, for each such Larry, print their full name.
counting
the number of people named"darryl"
that occur, and storing that count asdarryls-count
.- 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.
DEFECTS
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 ....
BOONS
But LOOP
is great because of ...
- Versatility: Even though it isn't extensible, it is still pretty darn versatile. With
LOOP
you cancollect
,append
count
,sum
,maximize
,minimize
; you run codewhen
orunless
orwhile
oruntil
some condition is true; you can check that a condition isalways
ornever
true, or thatthereis
at 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,
LOOP
expressions 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
LOOP
is frequently quite fast. Expressions expand into highly imperative code that usesBLOCK
,TAGBODY
,GO
, andSETQ
. 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.
LESSONS
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.LOOP
provides further evidence that Lisp is a truly multi-paradigm technology, one that that embraces practicality. That is,LOOP
may 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.
WRAP-UP
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 LOOP
.
Keep on hacking!
-colin