The dolist Macro

Suppose, for example, you want to reverse a list, so that “first” “second” “third” becomes “third” “second” “first”.

In practice, you would use the reverse function, like this:

(setq animals '(gazelle giraffe lion tiger))

(reverse animals)

Here is how you could reverse the list using a while loop:

(setq animals '(gazelle giraffe lion tiger))

(defun reverse-list-with-while (list)
  "Using while, reverse the order of LIST."
  (let (value)  ; make sure list starts empty
    (while list
      (setq value (cons (car list) value))
      (setq list (cdr list)))
    value))

(reverse-list-with-while animals)

And here is how you could use the dolist macro:

(setq animals '(gazelle giraffe lion tiger))

(defun reverse-list-with-dolist (list)
  "Using dolist, reverse the order of LIST."
  (let (value)  ; make sure list starts empty
    (dolist (element list value)
      (setq value (cons element value)))))

(reverse-list-with-dolist animals)

In Info, you can place your cursor after the closing parenthesis of each expression and type C-x C-e; in each case, you should see

(tiger lion giraffe gazelle)

in the echo area.

For this example, the existing reverse function is obviously best. The while loop is just like our first example (see A while Loop and a List). The while first checks whether the list has elements; if so, it constructs a new list by adding the first element of the list to the existing list (which in the first iteration of the loop is nil). Since the second element is prepended in front of the first element, and the third element is prepended in front of the second element, the list is reversed.

In the expression using a while loop, the (setq list (cdr list)) expression shortens the list, so the while loop eventually stops. In addition, it provides the cons expression with a new first element by creating a new and shorter list at each repetition of the loop.

The dolist expression does very much the same as the while expression, except that the dolist macro does some of the work you have to do when writing a while expression.

Like a while loop, a dolist loops. What is different is that it automatically shortens the list each time it loops—it CDRs down the list on its own—and it automatically binds the CAR of each shorter version of the list to the first of its arguments.

In the example, the CAR of each shorter version of the list is referred to using the symbol ‘element’, the list itself is called ‘list’, and the value returned is called ‘value’. The remainder of the dolist expression is the body.

The dolist expression binds the CAR of each shorter version of the list to element and then evaluates the body of the expression; and repeats the loop. The result is returned in value.