Common Lisp the Language, 2nd Edition


next up previous contents index
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.

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


[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 up previous contents index
Next: Mapping Up: Iteration Previous: General Iteration


AI.Repository@cs.cmu.edu