User Tools

A PCRE internal error occured. This might be caused by a faulty plugin

====== Macro DO, DO* ====== ====Syntax==== * **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//. ====Description==== **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//. ====Examples==== <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> </blockquote> 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. <blockquote> (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. <blockquote> (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> </blockquote> 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: <blockquote> ([[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> </blockquote> ====Affected By==== None. ====Exceptional Situations==== None. ====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]]** ====Notes==== 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: <blockquote> (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>//)))) </blockquote> **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. \issue{DECLS-AND-DOC} \issue{VARIABLE-LIST-ASYMMETRY:SYMMETRIZE}