User Tools


This shows you the differences between two versions of the page.

Link to this comparison view

cl:macros:do [2019/12/05 03:00]
cl:macros:do [2020/07/10 10:00] (current)
Line 1: Line 1:
 +====== Macro DO, DO* ======
 +  * **do** //({var | (var [init-form [step-form]])}''​*''​) (end-test-form result-form''​*''​) declaration''​*''​ {tag | statement}''​*''//​ → //​result''​*''//​
 +  * **do<​nowiki>​*</​nowiki>​** //({var | (var [init-form [step-form]])}''​*''​) (end-test-form result-form''​*''​) declaration''​*''​ {tag | statement}''​*''//​ → //​result''​*''//​
 +====Arguments and Values====
 +  * //var// - a //​[[CL:​Glossary:​symbol]]//​.
 +  * //​init-form//​ - a //​[[CL:​Glossary:​form]]//​.
 +  * //​step-form//​ - a //​[[CL:​Glossary:​form]]//​.
 +  * //​end-test-form//​ - a //​[[CL:​Glossary:​form]]//​.
 +  * //​result-forms//​ - an //​[[CL:​Glossary:​implicit progn]]//.
 +  * //​declaration//​ - a **[[CL:​Symbols:​declare]]** //​[[CL:​Glossary:​expression]]//;​ not evaluated.
 +  * //tag// - a //​[[CL:​Glossary:​go tag]]//; not evaluated.
 +  * //​statement//​ - a //​[[CL:​Glossary:​compound form]]//; evaluated as described below.
 +  * //results// - if a **[[CL:​Macros:​return]]** or **[[CL:​Macros:​return-from]]** form is executed, the //​[[CL:​Glossary:​values]]//​ passed from that //​[[CL:​Glossary:​form]]//;​ otherwise, the //​[[CL:​Glossary:​values]]//​ returned by the //​result-forms//​.
 +**do** iterates over a group of //​statements//​ while a test condition holds. **do** accepts an arbitrary number of iteration //vars// which are bound within the iteration and stepped in parallel. An initial value may be supplied for each iteration variable by use of an //​init-form//​. //​Step-forms//​ may be used to specify how the //vars// should be updated on succeeding iterations through the loop. //​Step-forms//​ may be used both to generate successive values or to accumulate results. If the //​end-test-form//​ condition is met prior to an execution of the body, the iteration terminates. //Tags// label //​statements//​.
 +**do<​nowiki>​*</​nowiki>​** is exactly like **do** except that the //​[[CL:​Glossary:​binding|bindings]]//​ and steppings of the //vars// are performed sequentially rather than in parallel.
 +Before the first iteration, all the //​init-forms//​ are evaluated, and each //var// is bound to the value of its respective //​init-form//,​ if supplied. This is a //​[[CL:​Glossary:​binding]]//,​ not an assignment; when the loop terminates, the old values of those variables will be restored. For **do**, all of the //​init-forms//​ are evaluated before any //var// is bound. The //​init-forms//​ can refer to the //​[[CL:​Glossary:​bindings]]//​ of the //vars// visible before beginning execution of **do**. For **do<​nowiki>​*</​nowiki>​**,​ the first //​init-form//​ is evaluated, then the first //var// is bound to that value, then the second //​init-form//​ is evaluated, then the second //var// is bound, and so on; in general, the ''​k''​th //​init-form//​ can refer to the new binding of the ''​j''​th //var// if ''​j''​ < ''​k'',​ and otherwise to the old binding of the ''​j''​th //var//.
 +At the beginning of each iteration, after processing the variables, the //​end-test-form//​ is evaluated. If the result is //​[[CL:​Glossary:​false]]//,​ execution proceeds with the body of the **do** (or **do<​nowiki>​*</​nowiki>​**) form. If the result is //​[[CL:​Glossary:​true]]//,​ the //​result-forms//​ are evaluated in order as an //​[[CL:​Glossary:​implicit progn]]//, and then **do** or **do<​nowiki>​*</​nowiki>​** returns.
 +At the beginning of each iteration other than the first, //vars// are updated as follows. All the //​step-forms//,​ if supplied, are evaluated, from left to right, and the resulting values are assigned to the respective //vars//. Any //var// that has no associated //​step-form//​ is not assigned to. For **do**, all the //​step-forms//​ are evaluated before any //var// is updated; the assignment of values to //vars// is done in parallel, as if by **[[CL:​Macros:​psetq]]**. Because all of the //​step-forms//​ are evaluated before any of the //vars// are altered, a //​step-form//​ when evaluated always has access to the old values of all the //vars//, even if other //​step-forms//​ precede it. For **do<​nowiki>​*</​nowiki>​**,​ the first //​step-form//​ is evaluated, then the value is assigned to the first //var//, then the second //​step-form//​ is evaluated, then the value is assigned to the second //var//, and so on; the assignment of values to variables is done sequentially,​ as if by **[[CL:​Special Operators:​setq]]**. For either **do** or **do<​nowiki>​*</​nowiki>​**,​ after the //vars// have been updated, the //​end-test-form//​ is evaluated as described above, and the iteration continues.
 +The remainder of the **do** (or **do<​nowiki>​*</​nowiki>​**) form constitutes an //​[[CL:​Glossary:​implicit tagbody]]//​. //Tags// may appear within the body of a **do** loop for use by **[[CL:​Special Operators:​go]]** statements appearing in the body (but such **[[CL:​Special Operators:​go]]** statements may not appear in the variable specifiers, the //​end-test-form//,​ or the //​result-forms//​). When the end of a **do** body is reached, the next iteration cycle (beginning with the evaluation of //​step-forms//​) occurs.
 +An //​[[CL:​Glossary:​implicit block]]// named **[[CL:​Constant Variables:​nil]]** surrounds the entire **do** (or **do<​nowiki>​*</​nowiki>​**) form. A **[[CL:​Macros:​return]]** statement may be used at any point to exit the loop immediately.
 +//​init-form//​ is an initial value for the //var// with which it is associated. If //​init-form//​ is omitted, the initial value of //var// is **[[CL:​Constant Variables:​nil]]**. If a //​declaration//​ is supplied for a //var//, //​init-form//​ must be consistent with the //​declaration//​.
 +//​declarations//​ can appear at the beginning of a **do** (or **do<​nowiki>​*</​nowiki>​**) body. They apply to code in the **do** (or **do<​nowiki>​*</​nowiki>​**) body, to the //​[[CL:​Glossary:​bindings]]//​ of the **do** (or **do<​nowiki>​*</​nowiki>​**) //vars//, to the //​step-forms//,​ to the //​end-test-form//,​ and to the //​result-forms//​.
 +<​blockquote> ​
 +(do ((temp-one 1 ([[CL:​Functions:​math-one-plus|1+]] temp-one)) ​
 +     ​(temp-two 0 ([[CL:​Functions:​math-one-minus|1-]] temp-two)))
 +    (([[CL:​Functions:​math-greater|>​]] ([[CL:​Functions:​math-subtract|-]] temp-one temp-two) 5) temp-one)) <​r>​4</​r>​
 +(do ((temp-one 1 ([[CL:​Functions:​math-one-plus|1+]] temp-one)) ​
 +     ​(temp-two 0 ([[CL:​Functions:​math-one-plus|1+]] temp-one))) ​
 +    (([[CL:​Functions:​math-equal|=]] 3 temp-two) temp-one)) <​r>​3</​r>​
 +(do* ((temp-one 1 ([[CL:​Functions:​math-one-plus|1+]] temp-one)) ​
 +      (temp-two 0 ([[CL:​Functions:​math-one-plus|1+]] temp-one))) ​
 +     ​(([[CL:​Functions:​math-equal|=]] 3 temp-two) temp-one)) <​r>​2</​r>​
 +(do ((j 0 ([[CL:​Functions:​math-add|+]] j 1))) 
 +    ([[CL:​Constant Variables:​nil]]) ;Do forever. ​
 +  ([[CL:​Functions:​format]] [[CL:​Constant Variables:​t]] "​~%Input ~D:" j)
 +  ([[CL:​Special Operators:​let]] ((item ([[CL:​Functions:​read]])))
 +    ([[CL:​Special Operators:​if]] ([[CL:​Functions:​null]] item) 
 +        ([[CL:​Macros:​return]]) ;Process items until NIL seen. 
 +        ([[CL:​Functions:​format]] [[CL:​Constant Variables:​t]] "​~&​Output ~D: ~S" j item))))
 +<​o>​Input 0: banana
 +Output 0: BANANA
 +Input 1: (57 boxes)
 +Output 1: (57 BOXES)
 +Input 2: [[CL:​Constant Variables:​nil|NIL]]</​o>​
 +<​r>​[[CL:​Constant Variables:​nil|NIL]]</​r>​
 +([[CL:​Macros:​defparameter]] *vector* ([[CL:​Functions:​vector]] 1 nil 3 nil))
 +(do ((i 0 ([[CL:​Functions:​math-one-plus|1+]] i)) ;Sets every null element of *vector* to zero. 
 +     (n ([[CL:​Functions:​array-dimension]] *vector* 0)))
 +    (([[CL:​Functions:​math-equal|=]] i n))
 +  ([[CL:​Macros:​when]] ([[CL:​Functions:​null]] ([[CL:​Functions:​aref]] *vector* i))
 +    ([[CL:​Macros:​setf]] ([[CL:​Functions:​aref]] *vector* i) 0)))
 +<​r>​[[CL:​Constant Variables:​nil|NIL]] </r>
 +*vector* <​r>#​(1 0 3 0)</​r>​
 +The below is an example of parallel assignment to index variables. On the first iteration, the value of ''​oldx''​ is whatever value ''​x''​ had before the **do** was entered. On succeeding iterations, ''​oldx''​ contains the value that ''​x''​ had on the previous iteration.
 +(do ((x e ([[CL:​Functions:​cdr]] x)) 
 +     (oldx x x))
 +    (([[CL:​Functions:​null]] x))
 +  body) 
 +</​blockquote> ​
 +The below does the same thing as ''​(mapcar #'f foo bar)''​. The step computation for ''​z''​ is an example of the fact that variables are stepped in parallel. Also, the body of the loop is empty.
 +(do ((x foo ([[CL:​Functions:​cdr]] x))
 +     (y bar ([[CL:​Functions:​cdr]] y)) 
 +     (z '() ([[CL:​Functions:​cons]] (f ([[CL:​Functions:​car]] x) ([[CL:​Functions:​car]] y)) z)))
 +    (([[CL:​Macros:​or]] ([[CL:​Functions:​null]] x) ([[CL:​Functions:​null]] y))
 +     ​([[CL:​Functions:​nreverse]] z)))
 +</​blockquote> ​
 +An example implementation of a list-reversing function could be:
 +<​blockquote> ​
 +([[CL:​Macros:​defun]] list-reverse (list) ​
 +  (do ((x list ([[CL:​Functions:​cdr]] x)) 
 +       (y '() ([[CL:​Functions:​cons]] ([[CL:​Functions:​car]] x) y))) 
 +      (([[CL:​Functions:​endp]] x) y))) <​r>​LIST-REVERSE</​r>​
 +As an example of nested iterations, consider a data structure that is a //​[[CL:​Glossary:​list]]//​ of //​[[CL:​Glossary:​cons|conses]]//​. The //​[[CL:​Glossary:​car]]//​ of each //​[[CL:​Glossary:​cons]]//​ is a //​[[CL:​Glossary:​list]]//​ of //​[[CL:​Glossary:​symbol|symbols]]//,​ and the //​[[CL:​Glossary:​cdr]]//​ of each //​[[CL:​Glossary:​cons]]//​ is a //​[[CL:​Glossary:​list]]//​ of equal length containing corresponding values. Such a data structure is similar to an association list, but is divided into "​frames";​ the overall structure resembles a rib-cage. A lookup function on such a data structure might be:
 +([[CL:​Macros:​defun]] ribcage-lookup (sym ribcage)
 +  (do ((r ribcage ([[CL:​Functions:​cdr]] r))) 
 +      (([[CL:​Functions:​null]] r) [[CL:​Constant Variables:​nil]]) ​
 +    (do ((s ([[CL:​Functions:​caar]] r) ([[CL:​Functions:​cdr]] s)) 
 +         (v ([[CL:​Functions:​cdar]] r) ([[CL:​Functions:​cdr]] v)))
 +        (([[CL:​Functions:​null]] s)) 
 +      ([[CL:​Macros:​when]] ([[CL:​Functions:​eq]] ([[CL:​Functions:​car]] s) sym)
 +        ([[CL:​Special Operators:​return-from]] ribcage-lookup ([[CL:​Functions:​car]] v)))))) <​r>​RIBCAGE-LOOKUP</​r>​
 +====Affected By====
 +====Exceptional Situations====
 +====See Also====
 +  * Other iteration functions ​
 +    * **[[CL:​Macros:​dolist|Macro DOLIST]]**
 +    * **[[CL:​Macros:​dotimes|Macro DOTIMES]]**
 +    * **[[CL:​Macros:​loop|Macro LOOP]]**
 +  * More primitive functionality ​
 +    * **[[CL:​Special Operators:​tagbody|Special Operator TAGBODY]]**
 +    * **[[CL:​Special Operators:​go|Special Operator GO]]**
 +    * **[[CL:​Special Operators:​block|Special Operator BLOCK]]**
 +    * **[[CL:​Macros:​return|Macro RETURN]]**
 +    * **[[CL:​Special Operators:​let|Special Operator LET]]**
 +    * **[[CL:​Special Operators:​setq|Special Operator SETQ]]**
 +If //​end-test-form//​ is **[[CL:​Constant Variables:​nil]]**,​ the test will never succeed. This provides an idiom for "do forever":​ the body of the **do** or **do<​nowiki>​*</​nowiki>​** is executed repeatedly. The infinite loop can be terminated by the use of **[[CL:​Macros:​return]]**,​ **[[CL:​Special Operators:​return-from]]**,​ **[[CL:​Special Operators:​go]]** to an outer level, or **[[CL:​Special Operators:​throw]]**.
 +A **do** //​[[CL:​Glossary:​form]]//​ may be explained in terms of the more primitive //​[[CL:​Glossary:​form|forms]]//​ **[[CL:​Special Operators:​block]]**,​ **[[CL:​Macros:​return]]**,​ **[[CL:​Special Operators:​let]]**,​ **[[CL:​Macros:​loop]]**,​ **[[CL:​Special Operators:​tagbody]]**,​ and **[[CL:​Macros:​psetq]]** as follows:
 +(block nil 
 +  (let ((//​var<​sub>​1</​sub>​ init<​sub>​1</​sub>​)// ​
 +        (//​var<​sub>​2</​sub>​ init<​sub>​2</​sub>//​) ​
 +        ... 
 +        (//​var<​sub>​n</​sub>​ init<​sub>​n</​sub>//​)) ​
 +    //​declarations//​
 +    (loop 
 +      (when //​end-test//​ (return (progn . //​result//​))) ​
 +      (tagbody . //​tagbody//​) ​
 +      (psetq //​var<​sub>​1</​sub>​ step<​sub>​1</​sub>//​
 +             //​var<​sub>​2</​sub>​ step<​sub>​2</​sub>//​
 +             ...
 +             //​var<​sub>​n</​sub>​ step<​sub>​n</​sub>//​))))
 +**do<​nowiki>​*</​nowiki>​** is similar, except that **[[CL:​Special Operators:​let*]]** and **[[CL:​Special Operators:​setq]]** replace the **[[CL:​Special Operators:​let]]** and **[[CL:​Macros:​psetq]]**,​ respectively.