Common Lisp the Language, 2nd Edition

Next: Mapping Up: Iteration Previous: General Iteration

## 7.8.3. Simple Iteration Constructs

The constructs `dolist` and `dotimes` execute a body of code once for each value taken by a single variable. They are expressible in terms of `do`, but capture very common patterns of use.

Both `dolist` and `dotimes` perform a body of statements repeatedly. On each iteration a specified variable is bound to an element of interest that the body may examine. `dolist` examines successive elements of a list, and `dotimes` examines integers from 0 to n-1 for some specified positive integer n.

The value of any of these constructs may be specified by an optional result form, which if omitted defaults to the value `nil`.

The `return` statement may be used to return immediately from a `dolist` or `dotimes` form, discarding any following iterations that might have been performed; in effect, a `block` named `nil` surrounds the construct. The body of the loop is implicitly a `tagbody` construct; it may contain tags to serve as the targets of `go` statements. Declarations may appear before the body of the loop.

[Macro]

    dolist (var listform [resultform])
           {declaration}* {tag | statement}*

`dolist` provides straightforward iteration over the elements of a list. First `dolist` evaluates the form listform, which should produce a list. It then executes the body once for each element in the list, in order, with the variable var bound to the element. Then resultform (a single form, not an implicit `progn`) is evaluated, and the result is the value of the `dolist` form. (When the resultform is evaluated, the control variable var is still bound and has the value `nil`.) If resultform is omitted, the result is `nil`.

    (dolist (x '(a b c d)) (prin1 x) (princ " ")) => nil
       after printing ``a b c d '' (note the trailing space)

An explicit `return` statement may be used to terminate the loop and return a specified value.

X3J13 voted in January 1989 (MAPPING-DESTRUCTIVE-INTERACTION) to restrict user side effects; see section 7.9.

[Macro]

    dotimes (var countform [resultform])
            {declaration}* {tag | statement}*

`dotimes` provides straightforward iteration over a sequence of integers. The expression `(dotimes (var countform resultform) . progbody)` evaluates the form countform, which should produce an integer. It then performs progbody once for each integer from zero (inclusive) to count (exclusive), in order, with the variable var bound to the integer; if the value of countform is zero or negative, then the progbody is performed zero times. Finally, resultform (a single form, not an implicit `progn`) is evaluated, and the result is the value of the `dotimes` form. (When the resultform is evaluated, the control variable var is still bound and has as its value the number of times the body was executed.) If resultform is omitted, the result is `nil`.

An explicit `return` statement may be used to terminate the loop and return a specified value.

Here is an example of the use of `dotimes` in processing strings:

    ;;; True if the specified subsequence of the string is a
    ;;; palindrome (reads the same forwards and backwards).

    (defun palindromep (string &optional
                               (start 0)
                               (end (length string)))
      (dotimes (k (floor (- end start) 2) t)
        (unless (char-equal (char string (+ start k))
                            (char string (- end k 1)))
          (return nil))))

    (palindromep "Able was I ere I saw Elba") => t

    (palindromep "A man, a plan, a canal-Panama!") => nil

    (remove-if-not #'alpha-char-p     ;Remove punctuation
                   "A man, a plan, a canal-Panama!")
       => "AmanaplanacanalPanama"

    (palindromep
     (remove-if-not #'alpha-char-p
                    "A man, a plan, a canal-Panama!")) => t

    (palindromep
     (remove-if-not
       #'alpha-char-p
       "Unremarkable was I ere I saw Elba Kramer, nu?")) => t

    (palindromep
     (remove-if-not
       #'alpha-char-p
       "A man, a plan, a cat, a ham, a yak,
                       a yam, a hat, a canal-Panama!")) => t

    (palindromep
     (remove-if-not
       #'alpha-char-p
       "Ja-da, ja-da, ja-da ja-da jing jing jing")) => nil

Altering the value of var in the body of the loop (by using `setq`, for example) will have unpredictable, possibly implementation-dependent results. A Common Lisp compiler may choose to issue a warning if such a variable appears in a `setq`.

Compatbility note: The `dotimes` construct is the closest thing in Common Lisp to the Interlisp `rptq` construct.

See also `do-symbols`, `do-external-symbols`, and `do-all-symbols`.

Next: Mapping Up: Iteration Previous: General Iteration