Up: Iteration   [Contents][Index]


16.4.13.1 do Macro

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.


Up: Iteration   [Contents][Index]