NIL
DOTIMES
is the high-level looping construct for counting loops. The basic template is much the same as DOLIST
's.
(dotimes (
The
CL-USER> (dotimes (i 4) (print i))
0
1
2
3
NIL
As with DOLIST
, you can use RETURN
to break out of the loop early.
Because the body of both DOLIST
and DOTIMES
loops can contain any kind of expressions, you can also nest loops. For example, to print out the times tables from 1 ? 1 = 1
to 20 ? 20 = 400
, you can write this pair of nested DOTIMES
loops:
(dotimes (x 20)
(dotimes (y 20)
(format t '~3d ' (* (1+ x) (1+ y))))
(format t '~%'))
While DOLIST
and DOTIMES
are convenient and easy to use, they aren't flexible enough to use for all loops. For instance, what if you want to step multiple variables in parallel? Or use an arbitrary expression to test for the end of the loop? If neither DOLIST
nor DOTIMES
meet your needs, you still have access to the more general DO
loop.
Where DOLIST
and DOTIMES
provide only one loop variable, DO
lets you bind any number of variables and gives you complete control over how they change on each step through the loop. You also get to define the test that determines when to end the loop and can provide a form to evaluate at the end of the loop to generate a return value for the DO
expression as a whole. The basic template looks like this:
(do (
(
Each
(
The LET
, if the NIL
. Also as with LET
, you can use a plain variable name as shorthand for a list containing just the name.
At the beginning of each iteration, after all the loop variables have been given their new values, the NIL
, the iteration proceeds, evaluating the
When the DO
expression.
At each step of the iteration the step forms for all the variables are evaluated before assigning any of the values to the variables. This means you can refer to any of the other loop variables in the step forms.[90] That is, in a loop like this:
(do ((n 0 (1+ n))
(cur 0 next)
(next 1 (+ cur next)))
((= 10 n) cur))
the step forms (1+ n)
, next
, and (+ cur next)
are all evaluated using the old values of n
, cur
, and next
. Only after all the step forms have been evaluated are the variables given their new values. (Mathematically inclined readers may notice that this is a particularly efficient way of computing the eleventh Fibonacci number.)
This example also illustrates another characteristic of DO
—because you can step multiple variables, you often don't need a body at all. Other times, you may leave out the result form, particularly if you're just using the loop as a control construct. This flexibility, however, is the reason that DO
expressions can be a bit cryptic. Where exactly do all the parentheses go? The best way to understand a DO
expression is to keep in mind the basic template.
(do (
(
The six parentheses in that template are the only ones required by the DO
itself. You need one pair to enclose the variable declarations, one pair to enclose the end test and result forms, and one pair to enclose the whole expression. Other forms within the DO
may require their own parentheses—variable definitions are usually lists, for instance. And the test form is often a function call. But the skeleton of a DO
loop will always be the same. Here are some example DO
loops with the skeleton in bold:
(do ((i 0 (1+ i)))
((>= i 4))
(print i))
Notice that the result form has been omitted. This is, however, not a particularly idiomatic use of DO
, as this loop is much more simply written using DOTIMES
.[91]
(dotimes (i 4) (print i))
As another example, here's the bodiless Fibonacci-computing loop:
(do ((n 0 (1+ n))
(cur 0 next)
(next 1 (+ cur next)))