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 SETFing 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) ==> undefined

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, The Empire Strikes Back

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 always 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 Hackers &

Вы читаете Practical Common Lisp
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату