Next: Trivial Operators Examples, Previous: COLLECTING/WITH-COLLECTORS Examples, Up: LOOP --> Loopless
for* ExamplesFirst, here's a trivial example of using “for-as-arithmetic” outside
of loop with for*. There is a frequent need to have
arithmetic stepping of a variable. Thanks to for*, you can
combine loop's intuitive syntax for this with any looping
construct whatsoever. You simply have to wrap the body of the loop
with for* and then call step* at the start of each
iteration.
(mapcar (for* ((i downfrom 10 by 3))
(lambda (element)
(step*)
(list element i (* i 10))))
'(a b c))
==
(loop for element in '(a b c)
for i downfrom 10 by 3
collect (list element i (* i 10)))
⇒ ((A 10 100) (B 7 70) (C 4 40))
This next example is illustrative of the following aspects
of typical for* usage:
for*. We'll usually have only one or two. We could have
put the square binding up there (right below the firstp
binding) as (square = (* i i)), but that would have been
gratuitous. We should get back into idiomatic Common Lisp as soon as
possible with good old plain oatmeal let.
for* was included in Loopless despite being unidiomatic because
it's so often useful (if you want to ditch loop). As such, it
should be used only when necessary.
Note that there's no other good way to do the stepping of i and
firstp here (assuming we don't want to fall back to
loop). Try doing the same without for* and see where
that leads you (the multiple references to i are especially
problematic).
for* never itself terminates looping (more formally, it never
initiates a non-local exit). As such, it always only provides some
stepping support for another looping construct (in this case
mapcar) without “overriding” its semantics.
for* should always “wrap” the body of the loop as close as
possible. Here, it's around the lambda (as it should be), not
the mapcar. This avoids needlessly exposing bindings and
obviously puts the bindings closer to the looping construct's body,
which is appropriate.
Note that we couldn't have put the step* call as the first
statement in the let, because then we would have accessed
i, a for* binding, before step* has been called at
least once, with undefined consequences.
(mapcar (for* ((i from 1)
(firstp = t then nil))
(lambda (symbol)
(step*)
(let ((square (* i i)))
(list i
symbol
(if firstp
'first
square)
(- square)))))
'(a b c))
Here's a big unrealistic example of for* usage that
illustrates most of its features. In most situations, you'll use (and
need) one or two for* bindings at a time only.
(mapcar (for* ((i downfrom (expt 2 5) by 3)
(oddp = (oddp i))
(j from 0)
(firstp = t then nil)
(k downfrom 0 by 2))
(lambda (element)
(step*)
`((element ,element) (i ,i) (oddp ,oddp)
(j ,j) (firstp ,firstp) (k ,k)
((+ i j k) ,(+ i j k)))))
'(a b c))
==
(loop for element in '(a b c)
for i downfrom (expt 2 5) by 3
for oddp = (oddp i)
for j from 0
for firstp = t then nil
for k downfrom 0 by 2
collect `((element ,element)
(i ,i) (oddp ,oddp)
(j ,j) (firstp ,firstp) (k ,k)
((+ i j k) ,(+ i j k))))
⇒
(((ELEMENT A) (I 32) (ODDP NIL) (J 0) (FIRSTP T) (K 0) ((+ I J K) 32))
((ELEMENT B) (I 29) (ODDP T) (J 1) (FIRSTP NIL) (K -2) ((+ I J K) 28))
((ELEMENT C) (I 26) (ODDP NIL) (J 2) (FIRSTP NIL) (K -4) ((+ I J K) 24)))