type: special form (fsubr) location: built-in source file: xlcont.c Common LISP compatible: yes supported on: all machines
(do* ( [ <binding> ... ] ) ( <test-expr> [ <result> ] ) [ <expr> ... ] ) <binding> - a variable binding which is can take one of the following forms: <symbol> ( <symbol> <init-expr> [<step-expr>] ) <symbol> - a symbol <init-expr> - an initialization expression for <symbol> <step-expr> - an expression that <symbol> symbol is updated at the end of each loop <test-expr> - an expression to test for loop termination <result> - an optional expression for the returned result <expr> - expressions comprising the body of the loop which may contain RETURNs, GOs or tags for GO
The DO* special form is basically a 'while' looping construct that contains symbols (with optional initializations and updates), a loop test (with an optional return value) and a block of code (expressions) to evaluate. The DO* form evaluates its initializations and updates in sequential order (as opposed to DO which doesn't). The sequence of these events is:
<init-expr> execution while <test-expr> do loop code execution <step-expr> execution end-while return <result>
The first form after the DO* is the 'binding' form. It contains a series of <symbol>'s or <binding>'s. The <binding> is a <symbol> followed by an initialization expression <init-expr> and an optional <step-expr>. If there is no <init-expr>, the <symbol> will be initialized to NIL. There is no specification as to the order of execution of the bindings or the step expressions - except that they happen all together.
The DO* form will go through and create and initialize the symbols. This is followed by evaluating the <test-expr>. If <test-expr> returns a non-NIL value, the loop will terminate. If <test-expr> returns a NIL value then the DO* will sequentially execute the <expr>'s. After execution of the loop <expr>'s, the <symbol>'s are set to the <step-expr>'s (if the <step-expr>'s exist). Then, the <test-expr> is re-evaluated, and so on.... The value of the <result> expression is evaluated and returned. If no <result> is specified, NIL is returned. When the DO* is finished execution, the <symbol>'s that were defined will no longer exist or retain their values.
(do ; DO example - won't work ((i 0) ; var I=0 (j i) ) ; var J=I (won't work) ( (eql i j) "done") ; test and result (print "looping")) ; error: unbound variable - I ; (do* ; DO* example - will work ((i 0) ; var I=0 (j i) ) ; var J=I (proper exec. order) ( (eql i j) "done") ; test and result (print "looping")) ; returns "done" (do* (i) ; DO* loop with var I ((eql i 0) "done") ; test and result (print i) (setq i 0) (print i)) ; prints NIL 0 ; returns "done" (do* (i) ; DO* loop with var I ((eql i 0)) ; test but no result (print i) (setq i 0) (print i)) ; prints NIL 0 ; returns NIL (do* ; DO* loop ((i 0 (setq i (1+ i))) ; var I=0 increment by 1 (j 10 (setq j (1- j))) ) ; var J=10 decrement by 1 ((eql i j) "met in the middle" ) ; test and result (princ i) (princ " ") ; prints 0 10 (princ j) (terpri)) ; 1 9 ; 2 8 ; 3 7 ; 4 6 ; returns "met in the middle"