You may wonder why LOOP
can't figure out whether it's looping over a list or a vector without needing different prepositions. This is another consequence of LOOP
being a macro: the value of the list or vector won't be known until runtime, but LOOP
, as a macro, has to generate code at compile time. And LOOP
's designers wanted it to generate extremely efficient code. To be able to generate efficient code for looping across, say, a vector, it needs to know at compile time that the value will be a vector at runtime—thus, the different prepositions are needed.
237
Don't ask me why LOOP
's authors chickened out on the no-parentheses style for the using
subclause.
238
The trick is to keep ahold of the tail of the list and add new cons cells by SETF
ing the CDR
of the tail. A handwritten equivalent of the code generated by (loop for i upto 10 collect i)
would look like this:
(do ((list nil) (tail nil) (i 0 (1+ i)))
((> i 10) list)
(let ((new (cons i nil)))
(if (null list)
(setf list new)
(setf (cdr tail) new))
(setf tail new)))
Of course you'll rarely, if ever, write code like that. You'll use either LOOP
or (if, for some reason, you don't want to use LOOP
) the standard PUSH
/NREVERSE
idiom for collecting values.
239
Recall that NCONC
is the destructive version of APPEND
—it's safe to use an nconc
clause only if the values you're collecting are fresh lists that don't share any structure with other lists. For instance, this is safe:
(loop for i upto 3 nconc (list i i)) ==> (0 0 1 1 2 2 3 3)
But this will get you into trouble:
(loop for i on (list 1 2 3) nconc i) ==>
The later will most likely get into an infinite loop as the various parts of the list produced by (list 1 2 3) are destructively modified to point to each other. But even that's not guaranteed—the behavior is simply undefined.
240
'No! Try not. Do . . . or do not. There is no try.' — Yoda,
241
I'm not picking on Perl here—this example would look pretty much the same in any language that bases its syntax on C's.
242
Perl would let you get away with not declaring those variables if your program didn't use strict
. But you should use strict
in Perl. The equivalent code in Python, Java, or C would always require the variables to be declared.
243
You can cause a loop to finish normally, running the epilogue, from Lisp code executed as part of the loop body with the local macro LOOP-FINISH
.
244
Some Common Lisp implementations will let you get away with mixing body clauses and for
clauses, but that's strictly undefined, and some implementations will reject such loops.
245
The one aspect of LOOP
I haven't touched on at all is the syntax for declaring the types of loop variables. Of course, I haven't discussed type declarations outside of LOOP
either. I'll cover the general topic a bit in Chapter 32. For information on how they work with LOOP
, consult your favorite Common Lisp reference.
246
Available at http://www.paulgraham.com/spam.html
and also in