{Begin SubSec The Iterative Statement}
{Title The Iterative Statement}
{Text


{Tag IterativeStatement}

{index *PRIMARY* Iterative statements}


The iterative statement (i.s.) in its various forms permits the user to specify complicated iterative statements in a straightforward and visible manner.  Rather than the user having to perform the mental transformations to an equivalent Interlisp form using {fn PROG}, {fn MAPC}, {fn MAPCAR}, etc., the system does it for him.  The goal was to provide a robust and tolerant facility which could "make sense" out of a wide class of iterative statements.  Accordingly, the user should not feel obliged to read and understand in detail the description of each operator given below in order to use iterative statements.

{index *PRIMARY* I.s.oprs}

An iterative statement is a form consisting of a number of special words (known as i.s. operators or i.s.oprs), followed by operands.  Many i.s.oprs ({lisp FOR}, {lisp DO}, {lisp WHILE}, etc.) are similar to iterative statements in other programming languages;  other i.s.oprs ({lisp COLLECT}, {lisp JOIN}, {lisp IN}, etc.) specify useful operations in a Lisp environment.  Lower case versions of i.s.oprs ({lisp do}, {lisp collect}, etc.) can also be used.  Here are some examples of iterative statements:

{lispcode
← (for X from 1 to 5 do (PRINT 'FOO))
FOO
FOO
FOO
FOO
FOO
NIL
← (for X from 2 to 10 by 2 collect (TIMES X X))
(4 16 36 64 100)
← (for X in '(A B 1 C 6.5 NIL (45)) count (NUMBERP X))
2}

{note other examples!!}


Iterative statements are implemented through CLISP, which translates the form into the appropriate {fn PROG}, {fn MAPCAR}, etc.  Iterative statement forms are translated using all CLISP declarations in effect (standard/fast/undoable/ etc.); see {PageRef Tag CLISPDeclarations}.  Misspelled i.s.oprs are recognized and corrected using the spelling list {var CLISPFORWORDSPLST}.{index CLISPFORWORDSPLST Var}{index spelling lists}  The order of appearance of operators is never important; CLISP scans the entire statement before it begins to construct the equivalent Interlisp form.  New i.s.oprs can be defined as described on {PageRef Fn I.S.OPR}.


If the user defines a function by the same name as an i.s.opr ({lisp WHILE}, {lisp TO}, etc.), the i.s.opr will no longer have the CLISP interpretation when it appears as {fn CAR} of a form, although it will continue to be treated as an i.s.opr if it appears in the interior of an iterative statement.  To alert the user, a warning message is printed, e.g., {lisp (WHILE DEFINED, THEREFORE DISABLED IN CLISP)}.{index DEFINED, THEREFORE DISABLED IN CLISP Error}

{note does this also happen if you redefine IF or ELSEIF??--yes!}



{Begin SubSec I.s.types}
{Title I.s.types}
{Text

{index *PRIMARY* I.s.types}

{Tag i.s.type}


The following i.s.oprs are examples of a certain kind of iterative statement operator called an i.s.type.  The i.s.type specifies what is to be done at each iteration.  Its operand is called the "body" of the iterative statement.  Each iterative statement must have one and only one i.s.type.



{Def {Type (I.S. Operator)}  {Name DO} {Args FORM}  {NoParens}
{Text
Specifies what is to be done at each iteration.  {lisp DO} with no other operator specifies an infinite loop.  If some explicit or implicit terminating condition is specified, the value of the i.s. is {lisp NIL}.  Translates to {fn MAPC} or {fn MAP} whenever possible.
}}



{Def {Type (I.S. Operator)}  {Name COLLECT} {Args FORM}  {NoParens}
{Text
Specifies that the value of {arg FORM} at each iteration is to be collected in a list, which is returned as the value of the i.s. when it terminates.  Translates to {fn MAPCAR}, {fn MAPLIST} or {fn SUBSET} whenever possible.

When {lisp COLLECT} translates to a {fn PROG} (e.g., if {lisp UNTIL}, {lisp WHILE}, etc. appear in the i.s.), the translation employs an open {fn TCONC} using two pointers similar to that used by the compiler for compiling {fn MAPCAR}.  To disable this translation, perform {lisp (CLDISABLE 'FCOLLECT)} (see {PageRef Fn CLDISABLE}).{index CLDISABLE Fn}
}}



{Def {Type (I.S. Operator)}  {Name JOIN} {Args FORM}  {NoParens}
{Text
Similar to {lisp COLLECT}, except that the values of {arg FORM} at each iteration are {fn NCONC}ed.  Translates to {fn MAPCONC} or {fn MAPCON} whenever possible.  {fn /NCONC}, {fn /MAPCONC}, and {fn /MAPCON} are used when the CLISP declaration {lisp UNDOABLE} is in effect.
}}



{Def {Type (I.S. Operator)}  {Name SUM} {Args FORM}  {NoParens}
{Text
Specifies that the values of {arg FORM} at each iteration be added together and returned as the value of the i.s., e.g., {lisp (for I from 1 to 5 sum (TIMES I I))} returns 1+4+9+16+25 = 55.  {fn IPLUS}, {fn FPLUS}, or {fn PLUS} will be used in the translation depending on the CLISP declarations in effect.
}}



{Def {Type (I.S. Operator)}  {Name COUNT} {Args FORM}  {NoParens}
{Text
Counts the number of times that {arg FORM} is true, and returns that count as its value.
}}



{Def {Type (I.S. Operator)}  {Name ALWAYS} {Args FORM}  {NoParens}
{Text
Returns {lisp T} if the value of {arg FORM} is non-{lisp NIL} for all iterations.  (Note: returns {lisp NIL} as soon as the value of {arg FORM} is {lisp NIL}).
}}



{Def {Type (I.S. Operator)}  {Name NEVER} {Args FORM}  {NoParens}
{Text
Similar to {lisp ALWAYS}, except returns {lisp T} if the value of {arg FORM} is {it never} true.  (Note: returns {lisp NIL} as soon as the value of {arg FORM} is non-{lisp NIL}).
}}


The following i.s.types explicitly refer to the iteration variable (i.v.) of the iterative statement, which is a variable set at each iteration.  This is explained below under {lisp FOR}.


{Def {Type (I.S. Operator)}  {Name THEREIS} {Args FORM}  {NoParens}
{Text
Returns the first value of the i.v. for which {arg FORM} is non-{lisp NIL}, e.g., {lisp (for X in Y thereis (NUMBERP X))} returns the first number in {lisp Y}.  (Note: returns the value of the i.v. as soon as the value of {arg FORM} is non-{lisp NIL}).
}}



{Def {Type (I.S. Operator)}  {Name LARGEST} {Args FORM}  {NoParens} }
{Def {Type (I.S. Operator)}  {Name SMALLEST} {Args FORM}  {NoParens}
{Text
Returns the value of the i.v. that provides the largest/smallest value of {arg FORM}.  {indexX {Name EXTREME} {Type Variable} {Text {lisp $$EXTREME}} } {index *PRIMARY* $$EXTREME Var}{lisp $$EXTREME} is always bound to the current greatest/smallest value, {indexX {Name VAL} {Type Variable} {Text {lisp $$VAL}} }{index *PRIMARY* $$VAL Var}{lisp $$VAL} to the value of the i.v. from which it came.
}}


}{End SubSec I.s.types}




{Begin SubSec Iteration Variable I.s.oprs}
{Title Iteration Variable I.s.oprs}
{Text


{Def {Type (I.S. Operator)}  {Name FOR} {Args VAR}  {NoParens}
{Text
Specifies the iteration variable (i.v.) which is used in conjunction with {lisp IN}, {lisp ON}, {lisp FROM}, {lisp TO}, and {lisp BY}.  The variable is rebound within the i.s., so the value of the variable outside the i.s. is not effected.  Example:

{lispcode
← (SETQ X 55)
55
← (for X from 1 to 5 collect (TIMES X X))
(1 4 9 16 25)
← X
55}
}}



{Def {Type (I.S. Operator)}  {Name FOR} {Args VARS}  {NoParens}
{Text
{arg VARS} a list of variables, e.g., {lisp (for (X Y Z) in {ellipsis})}.  The first variable is the i.v., the rest are dummy variables.  See {lisp BIND} below.
}}



{Def {Type (I.S. Operator)}  {Name FOR OLD} {Args VAR}  {NoParens}
{Text
Similar to {lisp FOR}, except that {arg VAR} is {it not} rebound within the i.s., so the value of the i.v. outside of the i.s. is changed.   Example:

{lispcode
← (SETQ X 55)
55
← (for old X from 1 to 5 collect (TIMES X X))
(1 4 9 16 25)
← X
6}
}}



{Def {Type (I.S. Operator)}  {Name BIND} {Args VAR}  {NoParens} }
{Def {Type (I.S. Operator)}  {Name BIND} {Args VARS}  {NoParens}
{Text
Used to specify dummy variables, which are bound locally within the i.s.
}}


Note:  {lisp FOR}, {lisp FOR OLD}, and {lisp BIND} variables can be initialized by using the form {lisp {arg VAR}←{arg FORM}}:

{lispcode (for old (X←{arg FORM}) bind (Y←{arg FORM}) {ellipsis})}


{Def {Type (I.S. Operator)}  {Name IN} {Args FORM}  {NoParens}
{Text
Specifies that the i.s. is to iterate down a list with the i.v. being reset to the corresponding element at each iteration.  For example, {lisp (for X in Y do {ellipsis})} corresponds to {lisp (MAPC Y (FUNCTION (LAMBDA (X) {ellipsis})))}.  If no i.v. has been specified, a dummy is supplied, e.g., {lisp (in Y collect CADR)} is equivalent to {lisp (MAPCAR Y (FUNCTION CADR))}.
}}



{Def {Type (I.S. Operator)}  {Name ON} {Args FORM}  {NoParens}
{Text
Same as {lisp IN} except that the i.v. is reset to the corresponding {it tail} at each iteration.  Thus {lisp IN} corresponds to {fn MAPC}, {fn MAPCAR}, and {fn MAPCONC}, while {lisp ON} corresponds to {fn MAP}, {fn MAPLIST}, and {fn MAPCON}.
}}



Note:  for both {lisp IN} and {lisp ON}, {arg FORM} is evaluated before the main part of the i.s. is entered, i.e. {it outside} of the scope of any of the bound variables of the i.s.  For example, {lisp (for X bind (Y←'(1 2 3)) in Y {ellipsis})} will map down the list which is the value of {lisp Y} evaluated {it outside} of the i.s., {it not} {lisp (1 2 3)}.



{Def {Type (I.S. Operator)}  {Name IN OLD} {Args VAR}  {NoParens}
{Text
{index IN (I.S. Operator)}{index OLD (I.S. Operator)}Specifies that the i.s. is to iterate down {arg VAR}, with {arg VAR} itself being reset to the corresponding tail at each iteration, e.g., after {lisp (for X in old L do {ellipsis} until {ellipsis})} finishes, {lisp L} will be some tail of its original value.
}}



{Def {Type (I.S. Operator)}  {Name IN OLD}
{PrintName {lisp IN OLD ({arg VAR}←{arg FORM})}}
{Text
{index OLD (I.S. Operator)}Same as {lisp IN OLD {arg VAR}}, except {arg VAR} is first set to value of {arg FORM}.
}}



{Def {Type (I.S. Operator)}  {Name ON OLD}  {Args VAR}  {NoParens}
{Text
{index ON (I.S. Operator)}{index OLD (I.S. Operator)}Same as {lisp IN OLD {arg VAR}} except the i.v. is reset to the current value of {arg VAR} at each iteration, instead of to {lisp (CAR {arg VAR})}.
}}



{Def {Type (I.S. Operator)}  {Name IN OLD}
{PrintName {lisp ON OLD ({arg VAR}←{arg FORM})}}
{Text
{index ON (I.S. Operator)}{index OLD (I.S. Operator)}Same as {lisp ON OLD {arg VAR}}, except {arg VAR} is first set to value of {arg FORM}.
}}



{Def {Type (I.S. Operator)}  {Name INSIDE}  {Args FORM}  {NoParens}
{Text
Similar to {lisp IN}, except treats first non-list, non-{lisp NIL} tail as the last element of the iteration, e.g., {lisp INSIDE '(A B C D . E)} iterates five times with the i.v. set to {lisp E} on the last iteration.  {lisp INSIDE 'A} is equivalent to {lisp INSIDE '(A)}, which will iterate once.
}}



{Def {Type (I.S. Operator)}  {Name FROM}  {Args FORM}  {NoParens}
{Text
Used to specify an initial value for a numerical i.v.  The i.v. is automatically incremented by 1 after each iteration (unless {index BY (I.S. Operator)}{lisp BY} is specified).  If no i.v. has been specified, a dummy i.v. is supplied and initialized, e.g., {lisp (from 2 to 5 collect SQRT)} returns {lisp (1.414 1.732 2.0 2.236)}.

{note need a simpler example....}
}}



{Def {Type (I.S. Operator)}  {Name TO}  {Args FORM}  {NoParens}
{Text
Used to specify the final value for a numerical i.v.  If {index FROM (I.S. Operator)}{lisp FROM} is not specified, the i.v. is initialized to 1.  If no i.v. has been specified, a dummy i.v. is supplied and initialized.  If {index BY (I.S. Operator)}{lisp BY} is not specified, the i.v. is automatically incremented by 1 after each iteration.  When the i.v. is definitely being {it incremented}, i.e., either {lisp BY} is not specified, or its operand is a positive number, the i.s. terminates when the i.v. exceeds the value of {arg FORM}.  Similarly, when the i.v. is definitely being decremented the i.s. terminates when the i.v. becomes {it less} than the value of {arg FORM} (see description of {lisp BY}).

Note:  {arg FORM} is evaluated only once, when the i.s. is first entered, and its value bound to a temporary variable against which the i.v. is checked each interation.  If the user wishes to specify an i.s. in which the value of the boundary condition is recomputed each iteration, he should use {lisp WHILE} or {lisp UNTIL} instead of {lisp TO}.
}}


Note:  When both the operands to {lisp TO} and {lisp FROM} are numbers, and {lisp TO}'s operand is less than {lisp FROM}'s operand, the i.v. is decremented by 1 after each iteration.  In this case, the i.s. terminates when the i.v. becomes {it less} than the value of {arg FORM}.  For example, {lisp (from 10 to 1 do PRINT)} prints the numbers from 10 down to 1.


{Def {Type (I.S. Operator)}  {Name BY}
{PrintName {lisp BY {arg FORM} {rm (with {lisp IN}/{lisp ON})}}}
{Text
If {index IN (I.S. Operator)}{lisp IN} or {index ON (I.S. Operator)}{lisp ON} have been specified, the value of {arg FORM} determines the {it tail} for the next iteration, which in turn determines the value for the i.v. as described earlier, i.e., the new i.v. is {fn CAR} of the tail for {lisp IN}, the tail itself for {lisp ON}.  In conjunction with {lisp IN}, the user can refer to the current tail within {arg FORM} by using the i.v. or the operand for {lisp IN}/{lisp ON},
e.g., {lisp (for Z in L by (CDDR {emphasize Z}) {ellipsis})} or
{lisp (for Z in L by (CDDR {emphasize L}) {ellipsis})}.
At translation time, the name of the internal variable which holds the value of the current tail is substituted for the i.v. throughout {arg FORM}.
For example, {lisp (for X in Y by (CDR (MEMB 'FOO (CDR X))) collect X)}
specifies that after each iteration, {fn CDR} of the current tail is to be searched for the atom {lisp FOO}, and ({fn CDR} of) this latter tail to be used for the next iteration.
}}



{Def {Type (I.S. Operator)}  {Name BY}
{PrintName {lisp BY {arg FORM} {rm (without {lisp IN}/{lisp ON})}}}
{Text
If {lisp IN} or {lisp ON} have not been used, {lisp BY} specifies how the i.v. itself is reset at each iteration.  If {index FROM (I.S. Operator)}{lisp FROM} or {index TO (I.S. Operator)}{lisp TO} have been specified, the i.v. is known to be numerical, so the new i.v. is computed by adding the value of {arg FORM} (which is reevaluated each iteration) to the current value of the i.v., e.g., {lisp (for N from 1 to 10 by 2 collect N)} makes a list of the first five odd numbers.

If {arg FORM} is a positive number ({arg FORM} itself, not its value, which in general CLISP would have no way of knowing in advance), the i.s. terminates when the value of the i.v. {it exceeds} the value of {lisp TO}'s operand.  If {arg FORM} is a negative number, the i.s. terminates when the value of the i.v. becomes {it less} than {lisp TO}'s operand,
e.g., {lisp (for I from N to M by -2 until (LESSP I M) {ellipsis})}.
Otherwise, the terminating condition for each iteration depends on the value of {arg FORM} for that iteration: if {arg FORM}<0, the test is whether the i.v. is less than {lisp TO}'s operand, if {arg FORM}>0 the test is whether the i.v. exceeds {lisp TO}'s operand, otherwise if {arg FORM}=0, the i.s. terminates unconditionally.

If {index FROM (I.S. Operator)}{lisp FROM} or {index TO (I.S. Operator)}{lisp TO} have not been specified and {arg FORM} is not a number, the i.v. is simply reset to the value of {arg FORM} after each iteration, e.g., {lisp (for I from N by M ...)} is equivalent to {lisp (for I←N by (PLUS I M) ...)}.

{note addition is done with IPLUS, FPLUS, or PLUS, according to current CLISP declarations}
}}



{Def {Type (I.S. Operator)}  {Name AS}  {Args VAR}  {NoParens}
{Text
Used to specify an iterative statement involving more than one iterative variable, e.g., {lisp (for X in Y as U in V do {ellipsis})} corresponds to {fn MAP2C} ({PageRef Fn MAP2C}).  The i.s. terminates when any of the terminating conditions are met, e.g.,
{lisp (for X in Y as I from 1 to 10 collect X)}
makes a list of the first ten elements of {lisp Y}, or however many elements there are on {lisp Y} if less than 10.

The operand to {index AS (I.S. Operator)}{lisp AS}, {arg VAR}, specifies the new i.v.
For the remainder of the i.s., or until another {lisp AS} is encountered, all operators refer to the new i.v.  For example,
{lisp (for I from 1 to N1 as J from 1 to N2 by 2 as K from N3 to 1 by -1 {ellipsis})}
terminates when {lisp I} exceeds {lisp N1}, or {lisp J} exceeds {lisp N2}, or {lisp K} becomes less than 1.  After each iteration, {lisp I} is incremented by 1, {lisp J} by 2, and {lisp K} by -1.
}}



{Def {Type (I.S. Operator)}  {Name OUTOF}  {Args FORM}  {NoParens}
{Text
For use with generators ({PageRef Tag Generators}).  On each iteration, the i.v. is set to successive values returned by the generator.  The i.s. terminates when the generator runs out.
}}


}{End SubSec Iteration Variable I.s.oprs}





{Begin SubSec Condition I.s.oprs}
{Title Condition I.s.oprs}
{Text


{Def {Type (I.S. Operator)}  {Name WHEN}  {Args FORM}  {NoParens}
{Text
Provides a way of excepting certain iterations.  For example, {lisp (for X in Y collect X when (NUMBERP X))} collects only the elements of {lisp Y} that are numbers.
}}



{Def {Type (I.S. Operator)}  {Name UNLESS}  {Args FORM}  {NoParens}
{Text
Same as {lisp WHEN} except for the difference in sign, i.e., {lisp WHEN Z} is the same as {lisp UNLESS (NOT Z)}.
}}



{Def {Type (I.S. Operator)}  {Name WHILE}  {Args FORM}  {NoParens}
{Text
Provides a way of terminating the i.s.  {lisp WHILE {arg FORM}} evaluates {arg FORM} {it before} each iteration, and if the value is {lisp NIL}, exits.
}}



{Def {Type (I.S. Operator)}  {Name UNTIL}  {Args FORM}  {NoParens}
{Text
Same as {lisp WHILE} except for difference in sign, i.e., {lisp WHILE X} is equivalent to {lisp UNTIL (NOT X)}.
}}



{Def {Type (I.S. Operator)}  {Name UNTIL}
{PrintName {lisp UNTIL {arg N}} ({arg N} a number)}
{Text
Equivalent to {lisp UNTIL {arg I.V.} > {arg N}}.
}}



{Def {Type (I.S. Operator)}  {Name REPEATWHILE}  {Args FORM}  {NoParens}
{Text
Same as {lisp WHILE} except the test is performed after the evalution of the body, but before the i.v. is reset for the next iteration.
}}



{Def {Type (I.S. Operator)}  {Name REPEATUNTIL}  {Args FORM}  {NoParens}
{Text
Same as {lisp UNTIL}, except the test is performed after the evaluation of the body.
}}



{Def {Type (I.S. Operator)}  {Name REPEATUNTIL}
{PrintName {lisp REPEATUNTIL {arg N}} ({arg N} a number)}
{Text
Equivalent to {lisp REPEATUNTIL {arg I.V.} > {arg N}}.
}}



}{End SubSec Condition I.s.oprs}




{Begin SubSec Other I.s.oprs}
{Title Other I.s.oprs}
{Text


{Def {Type (I.S. Operator)}  {Name FIRST}  {Args FORM}  {NoParens}
{Text
{arg FORM} is evaluated once before the first iteration, e.g., {lisp (for X Y Z in L first (FOO Y Z) {ellipsis})}, and {lisp FOO} could be used to initialize {lisp Y} and {lisp Z}.
}}



{Def {Type (I.S. Operator)}  {Name FINALLY}  {Args FORM}  {NoParens}
{Text
{arg FORM} is evaluated after the i.s. terminates.  For example,
{lisp (for X in L bind Y←0 do (if (ATOM X) then (SETQ Y (PLUS Y 1))) finally (RETURN Y))} will return the number of atoms in {lisp L}.
}}



{Def {Type (I.S. Operator)}  {Name EACHTIME}  {Args FORM}  {NoParens}
{Text
{arg FORM} is evaluated at the beginning of each iteration before, and regardless of, any testing.  For example, consider,

{lispcode
(for I from 1 to N
    do ({ellipsis} (FOO I) {ellipsis})
    unless ({ellipsis} (FOO I) {ellipsis})
    until ({ellipsis} (FOO I) {ellipsis}))}

The user might want to set a temporary variable to the value of {lisp (FOO I)} in order to avoid computing it three times each iteration.  However, without knowing the translation, he would not know whether to put the assignment in the operand to {lisp DO}, {lisp UNLESS}, or {lisp UNTIL}, i.e., which one would be executed first.  He can avoid this problem by simply writing {lisp EACHTIME (SETQ J (FOO I))}.
}}



{Def {Type (I.S. Operator)}  {Name DECLARE:}  {Args DECL}  {NoParens}
{Text
Inserts the form {lisp (DECLARE {arg DECL})} immediately following the {fn PROG} variable list in the translation, or, in the case that the translation is a mapping function rather than a {fn PROG}, immediately following the argument list of the lambda expression in the translation.  This can be used to declare variables bound in the iterative statement to be compiled as local or special variables (see {PageRef Var LOCALVARS}).  For example {lisp (for X in Y declare: (LOCALVARS X) {ellipsis})}.  Several {lisp DECLARE:}s can apppear in the same i.s.; the declarations are inserted in the order they appear.
}}



{Def {Type (I.S. Operator)}  {Name DECLARE}  {Args DECL}  {NoParens}
{Text
Same as {lisp DECLARE:}.

Note that since {fn DECLARE} is also the name of a function, {lisp DECLARE} cannot be used as an i.s. operator when it appears as {fn CAR} of a form, i.e. as the first i.s. operator in an iterative statement.  However, {lisp declare} (lower-case version) {it can} be the first i.s. operator.
}}



{Def {Type (I.S. Operator)}  {Name ORIGINAL}  {Args I.S.OPR OPERAND}  {NoParens}
{Text
{arg I.S.OPR} will be translated using its original, built-in interpretation, independent of any user defined i.s. operators.  See {PageRef FN I.S.OPR}.
}}



There are also a number of i.s.oprs that make it easier to create iterative statements that use the clock, looping for a given period of time.  See timers, {PageRef Tag Timers}.



}{End SubSec Other I.s.oprs}




{Begin SubSec Miscellaneous Hints on I.S.Oprs}
{Title Miscellaneous Hints on I.S.Oprs}
{Text


{Begin UnlabeledList Miscellaneous}

{Item
Lowercase versions of all i.s. operators are equivalent to the uppercase, e.g., {lisp (for X in Y {ellipsis})} is equivalent to {lisp (FOR X IN Y {ellipsis})}.
}


{Item
Each i.s. operator is of lower precedence than all Interlisp forms, so parentheses around the operands can be omitted, and will be supplied where necessary, e.g., {lisp BIND (X Y Z)} can be written {lisp BIND X Y Z, OLD (X←{arg FORM})} as {lisp OLD X←{arg FORM}}, {lisp WHEN (NUMBERP X)} as {lisp WHEN NUMBERP X}, etc.
}


{Item
{index RETURN (in iterative statement)}{lisp RETURN} or {index GO (in iterative statement)}{lisp GO} may be used in any
operand.  (In this case, the translation of the iterative statement will always be in the form of a {lisp PROG}, never a mapping function.)  {lisp RETURN} means return from the i.s. (with the indicated value), {it not} from the function in which the i.s appears.  {lisp GO} refers to a label elsewhere in the function in which the i.s. appears, except for the labels {lisp $$LP}, {lisp $$ITERATE}, and {lisp $$OUT} which are reserved, as described below.
}


{Item
In the case of {index FIRST (I.S. Operator)}{lisp FIRST}, {index FINALLY (I.S. Operator)}{lisp FINALLY}, {index EACHTIME (I.S. Operator)}{lisp EACHTIME}, {lisp DECLARE:} or one of the i.s.types, e.g., {lisp DO}, {lisp COLLECT}, {lisp SUM}, etc., the operand can consist of more than one form, e.g., {lisp COLLECT (PRINT (CAR X)) (CDR X)}, in which case a {lisp PROGN} is supplied.
}


{Item
Each operand can be the name of a function, in which case it is applied to the (last) i.v., e.g., {lisp (for X in Y do PRINT when NUMBERP)} is the same as {lisp (for X in Y do (PRINT X) when (NUMBERP X))}.  Note that the i.v. need not be explicitly specified, e.g., {lisp (in Y do PRINT when NUMBERP)} will work.

For i.s.types, e.g., {lisp DO}, {lisp COLLECT}, {lisp JOIN}, the function is always applied to the first i.v. in the i.s., whether explicity named or not.  For example, {lisp (in Y as I from 1 to 10 do PRINT)} prints elements on {lisp Y}, not integers between 1 and 10.

Note that this feature does not make much sense for {lisp FOR}, {lisp OLD}, {lisp BIND}, {lisp IN}, or {lisp ON}, since they "operate" before the loop starts, when the i.v. may not even be bound.

In the case of {index BY (I.S. Operator)}{lisp BY} in conjunction with {index IN (I.S. Operator)}{lisp IN}, the function is applied to the current {it tail} e.g., {lisp (for X in Y by CDDR {ellipsis})} is the same as {lisp (for X in Y by (CDDR X) {ellipsis})}.
}


{Item
While the exact form of the translation of an iterative statement depends on which operators are present, a {fn PROG} will always be used whenever the i.s. specifies dummy variables, i.e., if a {lisp BIND} operator appears, or there
is more than one variable specified by a {lisp FOR} operator, or a {fn GO}, {fn RETURN}, or a reference to the variable {lisp $$VAL}  appears in any of the operands.
When a {fn PROG} is used, the form of the translation is:

{lispcode
(PROG {arg VARIABLES}
      {bracket initialize}
$$LP  {bracket eachtime}
      {bracket test}
      {bracket body}
$$ITERATE
      {bracket aftertest}
      {bracket update}
      (GO $$LP)
$$OUT {bracket finalize}
      (RETURN $$VAL))}

where {lisp {bracket test}} corresponds to that portion of the loop that tests for termination and also for those iterations for which {lisp {bracket body}} is not going to be executed, (as indicated by a {lisp WHEN} or {lisp UNLESS});
{lisp {bracket body}} corresponds to the operand of the i.s.type, e.g., {lisp DO}, {lisp COLLECT}, etc.; {lisp {bracket aftertest}} corresponds to those tests for termination specified by {lisp REPEATWHILE} or {lisp REPEATUNTIL}; and {lisp {bracket update}} corresponds to that part that resets the tail, increments the counter, etc. in preparation for the next iteration.  {lisp {bracket initialize}}, {lisp {bracket finalize}}, and {lisp {bracket eachtime}} correspond to the
operands of {lisp FIRST}, {lisp FINALLY}, and {lisp EACHTIME}, if any.

Note that since {lisp {bracket body}} always appears at the top level of the {fn PROG}, the user can insert labels in {lisp {bracket body}}, and {fn GO} to them from within {lisp {bracket body}} or from other i.s. operands, e.g., {lisp (for X in Y first (GO A) do (FOO) A (FIE))}.  However, since {lisp {bracket body}} is dwimified as a list of forms, the label(s) should be added to the dummy variables for the iterative statement in order to prevent their being dwimified and possibly "corrected", e.g., {lisp (for X in Y bind A first (GO A) do (FOO) A (FIE))}.  The user can also {fn GO} to {lisp $$LP}, {lisp $$ITERATE}, or {lisp $$OUT}, or explicitly set {lisp $$VAL}.{index $$VAL Var}
}

{End UnlabeledList Miscellaneous}

}{End SubSec Miscellaneous Hints on I.S.Oprs}



{Begin SubSec Errors in Iterative Statements}
{Title Errors in Iterative Statements}
{Text

{index *PRIMARY* Errors in iterative statements}

An error will be generated and an appropriate diagnostic printed if any of the following conditions hold:

(1)  Operator with null operand, i.e., two adjacent operators, as in {lisp (for X in Y until do {ellipsis})}

(2)  Operand consisting of more than one form (except as operand to {lisp FIRST}, {lisp FINALLY}, or one of the i.s.types),
e.g., {lisp (for X in Y (PRINT X) collect {ellipsis})}.

(3)  {lisp IN}, {lisp ON}, {lisp FROM}, {lisp TO}, or {lisp BY} appear twice in same i.s.

(4)  Both {lisp IN} and {lisp ON} used on same i.v.

(5)  {lisp FROM} or {lisp TO} used with {lisp IN} or {lisp ON} on same i.v.

(6)  More than one i.s.type, e.g., a {lisp DO} and a {lisp SUM}.

In 3, 4, or 5, an error is not generated if an intervening {lisp AS} occurs.


If an error occurs, the i.s. is left unchanged.


If no {lisp DO}, {lisp COLLECT}, {lisp JOIN} or any of the other i.s.types are specified, CLISP will first attempt to find an operand consisting of more than one form, e.g., {lisp (for X in Y (PRINT X) when ATOM X {ellipsis})}, and in this case will insert a {lisp DO} after the first form.  (In this case, condition 2 is not considered to be met, and an error is not generated.)  If CLISP cannot find such an operand, and no {lisp WHILE} or {lisp UNTIL} appears in the i.s., a warning message is printed: {lisp NO DO, COLLECT, OR JOIN:} followed by the i.s.{index NO DO, COLLECT, OR JOIN Error}


Similarly, if no terminating condition is detected, i.e., no {lisp IN}, {lisp ON}, {lisp WHILE}, {lisp UNTIL}, {lisp TO}, or a {fn RETURN} or {fn GO}, a warning message is printed: {lisp POSSIBLE NON-TERMINATING ITERATIVE STATEMENT:}{index POSSIBLE NON-TERMINATING ITERATIVE STATEMENT Error} followed by the iterative statement.  However, since the user may be planning to terminate the i.s. via an error, control-E, or a {fn RETFROM} from a lower function, the i.s. is still translated.  Note:  The error message is not printed if the value of {var CLISPI.S.GAG}{index CLISPI.S.GAG Var} is {lisp T} (initially {lisp NIL}).

}{End SubSec Errors in Iterative Statements}



{Begin SubSec Defining New Iterative Statement Operators}
{Title Defining New Iterative Statement Operators}
{Text

{index *PRIMARY* Defining iterative statement operators}

The following function is available for defining new or redefining existing iterative statement operators:


{FnDef {FnName I.S.OPR} {FnArgs NAME FORM OTHERS EVALFLG}
{Text
{arg NAME} is the name of the new i.s.opr.  If {arg FORM} is a list, {arg NAME} will be a new {it i.s.type}{index I.s.types} (see {PageRef Tag i.s.type}), and {arg FORM} its body.

{arg OTHERS} is an (optional) list of additional i.s. operators and operands which will be added to the i.s. at the place where {arg NAME} appears.  If {arg FORM} is {lisp NIL}, {arg NAME} is a new i.s.opr defined entirely by {arg OTHERS}.

In both {arg FORM} and {arg OTHERS}, the atom {lisp $$VAL} can be used to reference the value to be returned by the i.s., {lisp I.V.} to reference the current i.v., and {lisp BODY} to reference {arg NAME}'s operand.  In other words, the current i.v. will be substituted for all instances of {lisp I.V.} and {arg NAME}'s operand will be substituted for all instances of {lisp BODY} throughout {arg FORM} and {arg OTHERS}.


If {arg EVALFLG} is {lisp T}, {arg FORM} and {arg OTHERS} are evaluated at translation time, and their values used as described above.  A dummy variable for use in translation that does not clash with a dummy variable already used by some other i.s. operators can be obtained by calling {lisp (GETDUMMYVAR)}.{index GETDUMMYVAR Fn} {lisp (GETDUMMYVAR T)} will return a dummy variable and also insure that it is bound as a {fn PROG} variable in the translation.

{note Should (GETDUMMYVAR BINDIT) be documented separately, with its own index entry?}


If {arg NAME} was previously an i.s.opr and is being redefined, the message {lisp ({arg NAME} REDEFINED)} will be printed (unless {var DFNFLG}={lisp T}), and all expressions using the i.s.opr {arg NAME} that have been translated will have their translations discarded.
}}


The following are some examples of how {fn I.S.OPR} could be called to define some existing i.s.oprs, and create some new ones:


{Begin LabeledList examples of the value of FORM}


{Label {lisp COLLECT}}
{Text
{lispcode
(I.S.OPR 'COLLECT
         '(SETQ $$VAL (NCONC1 $$VAL BODY)))}
}


{Label {lisp SUM}}
{Text
{lispcode
(I.S.OPR 'SUM
         '($$VAL←$$VAL+BODY)
         '(FIRST $$VAL←0))}

Note:  {lisp $$VAL+BODY} is used instead of {lisp (IPLUS $$VAL BODY)} so that the choice of function used in the translation, i.e., {fn IPLUS}, {fn FPLUS}, or {fn PLUS}, will be determined by the declarations then in effect.

{note bletch!! is there no way to do this without using CLISP infix operators??}
}


{Label {lisp NEVER}}
{Text
{lispcode
(I.S.OPR 'NEVER
         '(if BODY then $$VAL←NIL (GO $$OUT)))}

Note:  {lisp (if BODY then (RETURN NIL))} would exit from the i.s. immediately and therefore not execute the operations specified via a {lisp FINALLY} (if any).
}


{Label {lisp THEREIS}}
{Text
{lispcode
(I.S.OPR 'THEREIS
         '(if BODY then $$VAL←I.V. (GO $$OUT)))}
}


{Label {lisp RCOLLECT}}
{Text
To define {lisp RCOLLECT}, a version of {lisp COLLECT} which uses {fn CONS} instead of {fn NCONC1} and then reverses the list of values:

{lispcode
(I.S.OPR 'RCOLLECT
         '($$VAL←(CONS BODY $$VAL))
         '(FINALLY (RETURN (DREVERSE $$VAL)))]}
}


{Label {lisp TCOLLECT}}
{Text
To define {lisp TCOLLECT}, a version of {lisp COLLECT} which uses {fn TCONC}:

{lispcode
(I.S.OPR 'TCOLLECT
         '(TCONC $$VAL BODY)
         '(FIRST $$VAL←(CONS) FINALLY (RETURN (CAR $$VAL)))]}
}


{Label {lisp PRODUCT}}
{Text
{lispcode
(I.S.OPR 'PRODUCT
         '($$VAL←$$VAL*BODY)
         '(FIRST $$VAL←1)]}
}


{Label {lisp UPTO}}
{Text
To define {lisp UPTO}, a version of {lisp TO} whose operand is evaluated only once:

{lispcode
(I.S.OPR 'UPTO
         NIL
         '(BIND $$FOO←BODY TO $$FOO)]}
}


{Label {lisp TO}}
{Text
To redefine {lisp TO} so that instead of recomputing {arg FORM} each iteration, a variable is bound to the value of {arg FORM}, and then that variable is used:

{lispcode
(I.S.OPR 'TO
         NIL
         '(BIND $$END FIRST $$END←BODY ORIGINAL TO $$END)]}


Note the use of {index ORIGINAL (I.S. Operator)}{lisp ORIGINAL} to redefine {lisp TO} in terms of its original definition.  {lisp ORIGINAL} is intended for use in redefining built-in operators, since their definitions are not accessible, and hence not directly modifiable.  Thus if the operator had been defined by the user via {fn I.S.OPR}, {lisp ORIGINAL} would not obtain its original definition.  In this case, one presumably would simply modify the i.s.opr definition.
}


{End LabeledList examples of the value of FORM}



{fn I.S.OPR} can also be used to define synonyms for already defined i.s. operators by calling {fn I.S.OPR} with {arg FORM} an atom, e.g., {lisp (I.S.OPR 'WHERE 'WHEN)} makes {lisp WHERE} be the same as {lisp WHEN}.  Similarly, following {lisp (I.S.OPR 'ISTHERE 'THEREIS)}, one can write {lisp (ISTHERE ATOM IN Y)}, and following {lisp (I.S.OPR 'FIND 'FOR)} and {lisp (I.S.OPR 'SUCHTHAT 'THEREIS)}, one can write {lisp (find X in Y suchthat X member Z)}.  In the current system, {lisp WHERE}{index WHERE (I.S. Operator)} is synonymous with {lisp WHEN}, {lisp SUCHTHAT}{index SUCHTHAT (I.S. Operator)} and {lisp ISTHERE}{index ISTHERE (I.S. Operator)} with {lisp THEREIS}, {lisp FIND}{index FIND (I.S. Operator)} with {lisp FOR}, and {lisp THRU}{index THRU (I.S. Operator)} with {lisp TO}.


If {arg FORM} is the atom {lisp MODIFIER}{index MODIFIER Litatom}, then {arg NAME} is defined as an i.s.opr which can immediately follow another i.s. operator (i.e., an error will not be generated, as described previously).  {arg NAME} will not terminate the scope of the previous operator, and will be stripped off when {fn DWIMIFY} is called on its operand.  {lisp OLD} is an example of a {lisp MODIFIER} type of operator.  The {lisp MODIFIER} feature allows the user to define i.s. operators similar to {lisp OLD}, for use in conjunction with some other user defined i.s.opr which will produce the appropriate translation.


The file package command {lisp I.S.OPRS}{index I.S.OPRS FileCom} ({PageRef FileCom I.S.OPRS}) will dump the definition of i.s.oprs.  {lisp (I.S.OPRS PRODUCT UPTO)} as a file package command will print suitable expressions so that these iterative statement operators will be (re)defined when the file is loaded.



}{End SubSec Defining New Iterative Statement Operators}



{Begin Note}
Date: 15 FEB 1980 0015-PST
From: TEITELMAN

larry reported a serious problem in current loadup which is that any iteraive statement containing a COLLECT which does not translate into a mapcar, e.g. a collect with a WHILE or a BIND etc. does not dwimify correctly.

(1) there is a new loadup which I believe fixes the problem. Hoever, the fix was not straightforard and it is possible i may hve introduced a new problem. if anything develops while i am away, you can simply

(2) repair the fix in the current byte.sav by remproving the I.S.OPR property from fcollect (thereby causing it to translate using the (SETQ $$VAL (NCONC1 $$VAL body)) translation.

the problem stemmed from fcollect, which is the nly i.s.opr in the world which both evaluates its argument, and also defines an i.s.type. the problem is that it used to be handled by a kluge to take into account the fact that there wasnt anyay to compute the i.s.type so as to use a dummy variable, and also compute an expressionwhich bound the same dummy variable. similar i.s.oprs for inside used to do something like (SUBST (GENSYM) 'VAR exp) where exp included the BIND. but in fcollects case, this didnt work because the BIND and the i.s.type had to be handled separately.

I had fixed this up in general but not handled the fcollect case correctly.

In case any ofyou wish to use the new faciliy, which is somewhat cleaner, thre is now a functon called GETDUMMYVAR which is to be called from inside of an i.s.opr. It first takes variables from the list ($$TEM1 ... $$TEM6) and then uses GENSYM. If its argument is T, it ALSO effectively binds the variable, i.e. puts it in the progvars list. To see how it is used, look at the i.s.opr def for fcollect, and also for inside, outof etc.
{End Note}


{Begin Note}
Date:  7 FEB 1979 2239-PST
From: TEITELMAN
Subject: translation of iterative statements

ok, if FOO is not defined and has a macro, will translate to (FUNCTION (LAMBDA (X) (FOO X] rather than (FUNCTION FOO)
{End Note}


{Begin Note}
Date: 25 MAR 1977 2308-PST
From: TEITELMAN
Subject: internal iterative variables

not all of the information you want is available when you want it.  in fact puting in the EVAL form of i.s.opr took me about two weeks because the situation is as follows
(1) you cant dwimify their operands until the entire i.s. has been scanned and all the vars found
(2) but some i.s.oprs might contain BINDS etc. so is important to expand the i.s.oprs before dwimifying any of them, however
(3) one cannot substitute in the operands into the i.s.opr definitions until after dwiifying since othrwise any oerrors corrected in the operands wont be seen int he oriiginal i.s. furthermore
(4) if i subsitute in before dwimifying, i cant distinguish case where user wirtes a $$VAL, thereby requiring a PROG in the translation, or one comes as a result of an i.s.opr expansion such as collect.

now for the particulars of your requests:

if all you want to do is see if some other operator has been seen prevously in the i.s., this is simple. there is a variable called i.s.ptrs, which is a list of the i.s.oprs
seen.  CAR of each entry is the lowercase version of the i.s. (in the current lisp, this variable is called forptrs in case you want to experiment). so you can in fact determine if a dfor has been seen at the time of expanding a dbind.

the tail of the i.s. immediatel foollowing the operatr is also available at eval time, as is the tail of the i.s. as of the next operator, i.e. everything between the two tails (after dwiifying which doesnt happen till later) will be the body. the way you find this is each element on i.s.ptrs is of the form (opr tail1 tail2) where tail1 points into th i.s. as of opr (however, (CAR of thattail may not be equal to opr, e.g. CAR may be the uppercase version, opr the lower case, or in the caseof an i.s.type opr will be the atm i.s.type, but car of tail1 may be do, collect, etc.) tail2 points to he next opr. so what you want is cdr of tail1, i.e. (CDR (CADR (CAR LAST I.S.PTRS)))

note however that if you depend on this sort of thing, then for your dfor, you will have to either handle the cases (DFOR X INTEGER --) (DFOR (X INTEGER) --) (DFOR X ← & INTEGER ← & --) etc. all yourself, or else restrict yourself. 
{End Note}



}{End SubSec The Iterative Statement}