The `do`

macro is the fundamental iteration operator in Common Lisp. Like
`let`

, `do`

can create variables, and the first argument is a list of variable
specifications. Each element of this list can be of the form:

(variable initial update)

where *variable* is a symbol, and *initial* and *update* are expressions.
Initially, each *variable* will be set to the value of the corresponding
*initial*; on each iteration it will be set to the value of the corresponding
*update*. The `do`

in `show-squares`

creates just one variable, `i`

. On the
first iteration, `i`

will be set to the value of `start`

, and on successive
iterations its value will be incremented by one.

The second argument to `do`

should be a list containing one or more
expressions. The first expression is used to test whether iteration should
stop. In the cae above, the test expression is `(> i end)`

. The remaining
expressions in this list will be evaluated in order when iteration stops, and
the value of the last will be returned as the value of the `do`

.

The remaining arguments to `do`

comprise the body of the loop. They will be
evaluated, in order, on each iteration. On each iteration, the variables are
updated, then the termination test is evaluated, and then (if the test failed)
the body is evaluated.

For comparison, here is a recursive version of `show-squares`

:

(defun show-squares (i end) (if (> i end) 'done (progn (format t "~A ~A~%" i (( i i))) (show-squares (+ i 1) end))))

The only thing new in this function is `progn`

. It takes any number of
expressions, evaluates them in order, and returns the value of the last.

Common Lisp has simpler iteration operators for special cases. To iterate
through the elements of a list, for example, you would use `dolist`

. Here is a
function that returns the length of list:

(defun our-length (lst) (let ((len 0)) (dolist (obj lst) (setf len (+ len 1))) len))

Here, `dolist`

takes an argument of the form ‘`(variable expression)`’, followed
by a body of expressions. The body will be evaluated with *variable* bound to
successive elements of the list returned by *expression*. The obvious
recursive version of this function would be:

(defun our-length (lst) (if (null lst) 0 (+ (our-length (cdr lst)) 1)))

If the list is empty, its length is zero; otherwise it is the length of the cdr
plus one. This version of `our-length`

is cleaner, but because it’s not
tail-recursive, it won’t be as efficient.