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 'symbols' or 'bindings'. 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 'exprs'. After execution of the loop 'exprs', the 'symbols' are set to the step-exprs' [if the 'step-exprs' 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 'symbols' 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"
See the
do*
special form in the