First, here's a trivial example of using “for-as-arithmetic” outside
for*. There is a frequent need to have
arithmetic stepping of a variable. Thanks to
for*, you can
loop's intuitive syntax for this with any looping
construct whatsoever. You simply have to wrap the body of the loop
for* and then call
step* at the start of each
(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
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
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
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
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)))