I think you should avoid doing so, for two reasons.
Firstly as far as I can see the loop
specification makes no clear statement about whether this is safe, but dotimes
for instance says that
It is implementation-dependent whether dotimes
establishes a new binding of var on each iteration or whether it establishes a binding for var once at the beginning and then assigns it on any subsequent iterations.
In other words
(dotimes (i n)
... my code ...)
might expand to something like
(let (...)
...
(tagbody
start
(let ((i ...))
...my code...)
(unless ... (go start))
...))
for instance.
I suspect pretty strongly that loop
implementations don't do this in practice, and I think you probably could argue that the spec implies they are not allowed to do it, but I also think that the wording is not clear enough that you'd want to depend on that.
Secondly I think that as a matter of style adjusting the iteration variable's value inside the body of the iteration is, well, horrible: If someone reads (loop for i from 0 below 100 do ...)
they expect i to step by integers from 0 to 99, not to jump about randomly because of some devious obscurity in the code. So I would personally avoid this as a matter of style rather than as a matter of being sure the spec allows or does not say it is safe.
Rather I would do what Rainer suggested, which is (loop for x = ... then ...)
where it is clear that x
has values which are determined by your code, not by loop
.
Finally note that you can detect the iteration-variable-bound-on-each-iteration thing by, for instance:
> (mapcar #'funcall (loop for i below 3
collect (lambda () i)))
(3 3 3)
In this case the implementation I am using does not, in this case rebind it (but it might do in other cases of course!).
It's also worth noting that the possibility of assignment to loop control variables prevents an important optimisation being possible: loop unrolling. If the system can't assume that (loop for i from 0 to 2 do ...)
evaluates ...
three times, with i
being the appropriate value, you can't really unroll such a loop.
z
variable completely outside of the loop to make it clear thatz
is not the loop iteration counter.(let ((z 0)) (loop ... do (incf z) ... (if ... (setf z 0))))
. Thewith z = 0
is also OK imo, butfor z from 1
would definitely confuse people. – Titfer