[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25. "Clauses"

Internally, loop constructs a prog which includes variable bindings, pre-iteration (initialization) code, post-iteration (exit) code, the body of the iteration, and stepping of variables of iteration to their next values (which happens on every iteration after executing the body). A clause consists of the keyword symbol and any Lisp forms and keywords which it deals with. For example,
 
(loop for x in l do (print x)),
contains two clauses, "7for x in l" and "7do (print x)". Certain of the parts of the clause will be described as being expressions, e.g. (print x) in the above. An expression can be a single Lisp form, or a series of forms implicitly collected with progn. An expression is terminated by the next following atom, which is taken to be a keyword. This syntax allows only the first form in an expression to be atomic, but makes misspelled keywords more easily detectable. loop uses print-name equality to compare keywords so that loop forms may be written without package prefixes; in Lisp implementations that do not have packages, eq is used for comparison.

Bindings and iteration variable steppings may be performed either sequentially or in parallel, which affects how the stepping of one iteration variable may depend on the value of another. The syntax for distinguishing the two will be described with the corresponding clauses. When a set of things is "in parallel", all of the bindings produced will be performed in parallel by a single lambda binding. Subsequent bindings will be performed inside of that binding environment.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25.1 "Iteration-Driving Clauses"

These clauses all create a variable of iteration, which is bound locally to the loop and takes on a new value on each successive iteration. Note that if more than one iteration-driving clause is used in the same loop, several variables are created which all step together through their values; when any of the iterations terminates, the entire loop terminates. Nested iterations are not generated; for those, you need a second loop form in the body of the loop. In order to not produce strange interactions, iteration driving clauses are required to precede any clauses which produce "body" code: that is, all except those which produce prologue or epilogue code (initially and finally), bindings (with), the named clause, and the iteration termination clauses (while and until).

Clauses which drive the iteration may be arranged to perform their testing and stepping either in series or in parallel. They are by default grouped in series, which allows the stepping computation of one clause to use the just-computed values of the iteration variables of previous clauses. They may be made to step "in parallel", as is the case with the do special form, by "joining" the iteration clauses with the keyword and. The form this typically takes is something like
 
(loop ... for x = (f) and for y = init then (g x) ...)
which sets x to (f) on every iteration, and binds y to the value of init for the first iteration, and on every iteration thereafter sets it to (g x), where x still has the value from the previous iteration. Thus, if the calls to f and g are not order-dependent, this would be best written as
 
(loop ... for y = init then (g x) for x = (f) ...)
because, as a general rule, parallel stepping has more overhead than sequential stepping. Similarly, the example
 
(loop for sublist on some-list
      and for previous = 'undefined then sublist
      ...)
which is equivalent to the do construct
 
(do ((sublist some-list (cdr sublist))
     (previous 'undefined sublist))
    ((null sublist) ...)
  ...)
in terms of stepping, would be better written as
 
(loop for previous = 'undefined then sublist
      for sublist on some-list
      ...)

When iteration driving clauses are joined with and, if the token following the and is not a keyword which introduces an iteration driving clause, it is assumed to be the same as the keyword which introduced the most recent clause; thus, the above example showing parallel stepping could have been written as
 
(loop for sublist on some-list
      and previous = 'undefined then sublist
      ...)

The order of evaluation in iteration-driving clauses is that those expressions which are only evaluated once are evaluated in order at the beginning of the form, during the variable-binding phase, while those expressions which are evaluated each time around the loop are evaluated in order in the body.

One common and simple iteration driving clause is repeat:

repeat expression
.keyword_index repeat This evaluates expression (during the variable binding phase), and causes the loop to iterate that many times. expression is expected to evaluate to a fixnum. If expression evaluates to a zero or negative result, the body code will not be executed.

All remaining iteration driving clauses are subdispatches of the keyword for, which is synonomous with as. In all of them a variable of iteration is specified. Note that, in general, if an iteration driving clause implicitly supplies an endtest, the value of this iteration variable as the loop is exited (i.e., when the epilogue code is run) is undefined. (This is discussed in more detail in section (loop-iteration-framework-section).)

Here are all of the varieties of for clauses. Optional parts are enclosed in curly brackets. The data-types as used here are discussed fully in section (loop-data-type-section).

for var {data-type in expr1 {by expr2}}
.keyword_index for This iterates over each of the elements in the list expr1. If the by subclause is present, expr2 is evaluated once on entry to the loop to supply the function to be used to fetch successive sublists, instead of cdr.

for var {data-type on expr1 {by expr2}}
.keyword_index for This is like the previous for format, except that var is set to successive sublists of the list instead of successive elements. Note that since var will always be a list, it is not meaningful to specify a data-type unless var is a destructuring pattern, as described in the section on destructuring, (loop-destructuring-page). Note also that loop uses a null rather than an atom test to implement both this and the preceding clause.

for var {data-type = expr}
.keyword_index for On each iteration, expr is evaluated and var is set to the result.

for var {data-type = expr1 then expr2}
.keyword_index for var is bound to expr1 when the loop is entered, and set to expr2 (re-evaluated) at all but the first iteration. Since expr1 is evaluated during the binding phase, it cannot reference other iteration variables set before it; for that, use the following:

for var {data-type first expr1 then expr2}
.keyword_index for This sets var to expr1 on the first iteration, and to expr2 (re-evaluated) on each succeeding iteration. The evaluation of both expressions is performed inside of the loop binding environment, before the loop body. This allows the first value of var to come from the first value of some other iteration variable, allowing such constructs as
 
(loop for term in poly
      for ans first (car term) then (gcd ans (car term))
      finally (return ans))

for var {data-type from expr1 {to expr2} {by expr3}}
.keyword_index for @setq loop-arithmetic-stepping page This performs numeric iteration. var is initialized to expr1, and on each succeeding iteration is incremented by expr3 (default 1). If the to phrase is given, the iteration terminates when var becomes greater than expr2. Each of the expressions is evaluated only once, and the to and by phrases may be written in either order. downto may be used instead of to, in which case var is decremented by the step value, and the endtest is adjusted accordingly. If below is used instead of to, or above instead of downto, the iteration will be terminated before expr2 is reached, rather than after. Note that the to variant appropriate for the direction of stepping must be used for the endtest to be formed correctly; i.e. the code will not work if expr3 is negative or zero. If no limit-specifying clause is given, then the direction of the stepping may be specified as being decreasing by using downfrom instead of from. upfrom may also be used instead of from; it forces the stepping direction to be increasing. The data-type defaults to fixnum.

for var {data-type being expr and its path ...}
for var {data-type being {each|the} path ...}
.keyword_index for This provides a user-definable iteration facility. path names the manner in which the iteration is to be performed. The ellipsis indicates where various path dependent preposition/expression pairs may appear. See the section on Iteration Paths ((iteration-path-page)) for complete documentation.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25.2 "Bindings"

.setq with-clause page .keyword_index with The with keyword may be used to establish initial bindings, that is, variables which are local to the loop but are only set once, rather than on each iteration. The with clause looks like:
 
with var1 {data-type} {= expr1}
     {and var2 {data-type} {= expr2}}...
If no expr is given, the variable is initialized to the appropriate value for its data type, usually nil. with bindings linked by and are performed in parallel; those not linked are performed sequentially. That is,
 
(loop with a = (foo) and b = (bar) and c
      ...)
binds the variables like
 
((lambda (a b c) ...)
 (foo) (bar) nil)
whereas
 
(loop with a = (foo) with b = (bar a) with c ...)
binds the variables like
 
((lambda (a)
    ((lambda (b)
	((lambda (c) ...)
	 nil))
     (bar a)))
 (foo))
All expr's in with clauses are evaluated in the order they are written, in lambda expressions surrounding the generated prog. The loop expression
 
(loop with a = xa and b = xb
      with c = xc
      for d = xd then (f d)
	and e = xe then (g e d)
      for p in xp
      with q = xq
      ...)
produces the following binding contour, where t1 is a loop-generated temporary:
 
((lambda (a b)
    ((lambda (c)
	((lambda (d e)
	     ((lambda (p t1)
		  ((lambda (q) ...)
		   xq))
	      nil xp))
	 xd xe))
     xc))
 xa xb)
Because all expressions in with clauses are evaluated during the variable binding phase, they are best placed near the front of the loop form for stylistic reasons.

For binding more than one variable with no particular initialization, one may use the construct
 
with variable-list {data-type-list} {and ...}
as in
 
with (i j k t1 t2) (fixnum fixnum fixnum) ...
A slightly shorter way of writing this is
 
with (i j k) fixnum and (t1 t2) ...
These are cases of destructuring which loop handles specially; destructuring and data type keywords are discussed in sections (loop-destructuring-section) and (loop-data-type-section).

Occasionally there are various implementational reasons @setq loop-nodeclare-clause page for a variable not to be given a local type declaration. If this is necessary, the nodeclare clause may be used:

nodeclare variable-list
The variables in variable-list are noted by loop as not requiring local type declarations. Consider the following:
 
(declare (special k) (fixnum k))
(defun foo (l)
    (loop for x in l as k fixnum = (f x) ...))
If k did not have the fixnum data-type keyword given for it, then loop would bind it to nil, and some compilers would complain. On the other hand, the fixnum keyword also produces a local fixnum declaration for k; since k is special, some compilers will complain (or error out). The solution is to do:
 
(defun foo (l)
    (loop nodeclare (k)
	  for x in l as k fixnum = (f x) ...))
which tells loop not to make that local declaration. The nodeclare clause must come before any reference to the variables so noted. Positioning it incorrectly will cause this clause to not take effect, and may not be diagnosed.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25.3 "Entrance and Exit"

initially expression
.keyword_index initially This puts expression into the prologue of the iteration. It will be evaluated before any other initialization code other than the initial bindings. For the sake of good style, the initially clause should therefore be placed after any with clauses but before the main body of the loop.

finally expression
.keyword_index finally .setq loop-finally-clause page This puts expression into the epilogue of the loop, which is evaluated when the iteration terminates (other than by an explicit return). For stylistic reasons, then, this clause should appear last in the loop body. Note that certain clauses may generate code which terminates the iteration without running the epilogue code; this behavior is noted with those clauses. Most notable of these are those described in the section (aggregated-boolean-tests-section), Aggregated Boolean Tests. This clause may be used to cause the loop to return values in a non-standard way:
 
(loop for n in l
      sum n into the-sum
      count t into the-count
      finally (return (quotient the-sum the-count)))


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25.4 "Side Effects"

.setq side-effects-section css-number

do expression
doing expression
.keyword_index do doing expression is evaluated each time through the loop, as shown in the print-elements-of-list example on (print-elements-of-list-example).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25.5 "Values"

.setq values-section css-number The following clauses accumulate a return value for the iteration in some manner. The general form is
 
type-of-collection expr {data-type} {into var}
where type-of-collection is a loop keyword, and expr is the thing being "accumulated" somehow. If no into is specified, then the accumulation will be returned when the loop terminates. If there is an into, then when the epilogue of the loop is reached, var (a variable automatically bound locally in the loop) will have been set to the accumulated result and may be used by the epilogue code. In this way, a user may accumulate and somehow pass back multiple values from a single loop, or use them during the loop. It is safe to reference these variables during the loop, but they should not be modified until the epilogue code of the loop is reached. For example,
 
(loop for x in list
      collect (foo x) into foo-list
      collect (bar x) into bar-list
      collect (baz x) into baz-list
    finally (return (list foo-list bar-list baz-list)))
has the same effect as
 
(do ((g0001 list (cdr g0001))
     (x) (foo-list) (bar-list) (baz-list))
    ((null g0001)
     (list (nreverse foo-list)
	   (nreverse bar-list)
	   (nreverse baz-list)))
   (setq x (car g0001))
   (setq foo-list (cons (foo x) foo-list))
   (setq bar-list (cons (bar x) bar-list))
   (setq baz-list (cons (baz x) baz-list)))
except that loop arranges to form the lists in the correct order, obviating the nreverses at the end, and allowing the lists to be examined during the computation.

collect expr {into var}
collecting ...
.keyword_index collect collecting .setq collect-clause page This causes the values of expr on each iteration to be collected into a list.

nconc expr {into var}
nconcing ...
append ...
appending ...
.keyword_index nconc nconcing append appending These are like collect, but the results are nconced or appended together as appropriate.
 
(loop for i from 1 to 3
      nconc (list i (* i i)))
  => (1 1 2 4 3 9)

count expr {into var {data-type}}
counting ...
.keyword_index count counting If expr evaluates non-nil, a counter is incremented. The data-type defaults to fixnum.

sum expr {data-type {into var}}
summing ...
.keyword_index sum summing Evaluates expr on each iteration, and accumulates the sum of all the values. data-type defaults to number, which for all practical purposes is notype. Note that specifying data-type implies that both the sum and the number being summed (the value of expr) will be of that type.

maximize expr {data-type {into var}}
minimize ...
.keyword_index maximize minimize Computes the maximum (or minimum) of expr over all iterations. data-type defaults to number. Note that if the loop iterates zero times, or if conditionalization prevents the code of this clause from being executed, the result will be meaningless. If loop can determine that the arithmetic being performed is not contagious (by virtue of data-type being fixnum, flonum, or small-flonum), then it may choose to code this by doing an arithmetic comparison rather than calling either max or min. As with the sum clause, specifying data-type implies that both the result of the max or min operation and the value being maximized or minimized will be of that type.

Not only may there be multiple accumulations in a loop, but a single accumulation may come from multiple places within the same loop form. Obviously, the types of the collection must be compatible. collect, nconc, and append may all be mixed, as may sum and count, and maximize and minimize. For example,
 
(loop for x in '(a b c) for y in '((1 2) (3 4) (5 6))
      collect x
      append y)
  => (a 1 2 b 3 4 c 5 6)
.group The following computes the average of the entries in the list list-of-frobs:
 
(loop for x in list-of-frobs
      count t into count-var
      sum x into sum-var
    finally (return (quotient sum-var count-var)))
.end_group


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25.6 "Endtests"

.topic terminating the iteration The following clauses may be used to provide additional control over when the iteration gets terminated, possibly causing exit code (due to finally) to be performed and possibly returning a value (e.g., from collect).

while expr
.keyword_index while If expr evaluates to nil, the loop is exited, performing exit code (if any), and returning any accumulated value. The test is placed in the body of the loop where it is written. It may appear between sequential for clauses.

until expr
.keyword_index until Identical to while (not expr).

This may be needed, for example, to step through a strange data structure, as in
 
(loop until (top-of-concept-tree? concept)
      for concept = expr then (superior-concept concept)
      ...)
Note that the placement of the while clause before the for clause is valid in this case because of the definition of this particular variant of for, which binds concept to its first value rather than setting it from inside the loop.

The following may also be of use in terminating the iteration:

Macro: loop-finish
(loop-finish) causes the iteration to terminate "normally", the same as implicit termination by an iteration driving clause, or by the use of while or until--the epilogue code (if any) will be run, and any implicitly collected result will be returned as the value of the loop. For example,
 
(loop for x in '(1 2 3 4 5 6)
      collect x
      do (cond ((= x 4) (loop-finish))))
 => (1 2 3 4)
This particular example would be better written as until (= x 4) in place of the do clause.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25.7 "Aggregated Boolean Tests"

.setq aggregated-boolean-tests-section css-number All of these clauses perform some test, and may immediately terminate the iteration depending on the result of that test.

always expr
.keyword_index always Causes the loop to return t if expr always evaluates non-null. If expr evaluates to nil, the loop immediately returns nil, without running the epilogue code (if any, as specified with the finally clause); otherwise, t will be returned when the loop finishes, after the epilogue code has been run.

never expr
.keyword_index never Causes the loop to return t if expr never evaluates non-null. This is equivalent to always (not expr).

thereis expr
.keyword_index thereis If expr evaluates non-nil, then the iteration is terminated and that value is returned, without running the epilogue code.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25.8 "Conditionalization"

.topic conditionalizing clause(s) These clauses may be used to "conditionalize" the following clause. They may precede any of the side-effecting or value-producing clauses, such as do, collect, always, or return.

when expr
if expr
.keyword_index when if If expr evaluates to nil, the following clause will be skipped, otherwise not.

unless expr
.keyword_index unless This is equivalent to when (not expr)).

Multiple conditionalization clauses may appear in sequence. If one test fails, then any following tests in the immediate sequence, and the clause being conditionalized, are skipped.

Multiple clauses may be conditionalized under the same test by joining them with and, as in
 
(loop for i from a to b
      when (zerop (remainder i 3))
        collect i and do (print i))
which returns a list of all multiples of 3 from a to b (inclusive) and prints them as they are being collected.

If-then-else conditionals may be written using the else keyword, as in
 
(loop for i from a to b
      when (oddp i)
        collect i into odd-numbers
      else collect i into even-numbers)
Multiple clauses may appear in an else-phrase, using and to join them in the same way as above.

Conditionals may be nested. For example,
 
(loop for i from a to b
      when (zerop (remainder i 3))
	do (print i)
	and when (zerop (remainder i 2))
	      collect i)
returns a list of all multiples of 6 from a to b, and prints all multiples of 3 from a to b.

When else is used with nested conditionals, the "dangling else" ambiguity is resolved by matching the else with the innermost when not already matched with an else. Here is a complicated example.
 
(loop for x in l
      when (atom x)
	when (memq x *distinguished-symbols*)
	  do (process1 x)
	else do (process2 x)
      else when (memq (car x) *special-prefixes*)
	     collect (process3 (car x) (cdr x))
	     and do (memoize x)
           else do (process4 x))

Useful with the conditionalization clauses is the return clause, which causes an explicit return of its "argument" as the value of the iteration, bypassing any epilogue code. That is,
 
when expr1 return expr2
is equivalent to
 
when expr1 do (return expr2)
Conditionalization of one of the "aggregated boolean value" clauses simply causes the test which would cause the iteration to terminate early not to be performed unless the condition succeeds. For example,
 
(loop for x in l
      when (significant-p x)
	do (print x) (princ "is significant.")
	and thereis (extra-special-significant-p x))
does not make the extra-special-significant-p check unless the significant-p check succeeds.

.group The format of a conditionalized clause is typically something like
 
when expr1 keyword expr2
If expr2 is the keyword it, then a variable is generated to hold the value of expr1, and that variable gets substituted for expr2. Thus, the composition
 
when expr return it
is equivalent to the clause
 
thereis expr
and one may collect all non-null values in an iteration by saying
 
when expression collect it
If multiple clauses are joined with and, the it keyword may only be used in the first. If multiple whens, unlesses, and/or ifs occur in sequence, the value substituted for it will be that of the last test performed. The it keyword is not recognized in an else-phrase. .end_group


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

25.9 "Miscellaneous Other Clauses"

named name
.keyword_index named This gives the prog which loop generates a name of name, so that one may use the return-from form to return explicitly out of that particular loop:
 
(loop named sue
      ...
      do (loop ... do (return-from sue value) ...)
      ...)
The return-from form shown causes value to be immediately returned as the value of the outer loop. Only one name may be given to any particular loop construct. This feature does not exist in the Maclisp version of loop, since Maclisp does not support "named progs".

return expression
.keyword_index return Immediately returns the value of expression as the value of the loop, without running the epilogue code. This is most useful with some sort of conditionalization, as discussed in the previous section. Unlike most of the other clauses, return is not considered to "generate body code", so it is allowed to occur between iteration clauses, as in
 
(loop for entry in list
      when (not (numberp entry))
	return (error ...)
      as frob = (times entry 2)
      ...)
If one instead desires the loop to have some return value when it finishes normally, one may place a call to the return function in the epilogue (with the finally clause, (loop-finally-clause)).


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Brad Parker on June, 13 2006 using texi2html