Overview

The loop form in Common Lisp, version 2, is a powerful, if somewhat feature-laden, form for repeatedly executing a body of code. Most common iteration patterns can be written quite clearly with it. If you start using too many features at once, however, you can construct an unmaintainable mess. I describe here a subset of loop that should cover most of the needs of the class, and is available in the file loop.lisp for users of Common Lisp, version 1, e.g., Xlisp, Clisp or Kyoto Common Lisp. A complete version of loop is also available for Clisp and Kyoto Common Lisp. It's quite a large file. All of the features of loop are described in detail in Steele, Common Lisp, the Language, 2nd ed., and in Graham's ANSI Common LISP.

Basic Syntax

(loop clause
      clause
      ...)

where a clause has the form

loop-keyword item item ...

Here's a simple example. It prints the 1st, 3rd, 5th ... elements of the list l.

(defun loop-example (l)
  (loop for x in l
        for i from 1
        when (oddp i)
        do (print x)

For example, (loop-example '(a b c d)) would print a and c and return 4. Here's a table listing what each clause in the example above does:

Clause Effect

for x in l

steps x through the elements of l

for i from 1

steps i from 1, 2, 3, ...

when (oddp i) do (print x)

when i is odd, prints x

finally (return (length l))

when the loop finishes, returns the length of l

As you can see, a clause starts with a keyword, such as for or when, followed by expressions and possibly other keywords. Some clauses step variables through a set of values. That is, the variable will be set to a new value each time through the loop. The clause may or may not set up an exit condition to stop the loop. Other clauses say what to do and when to do it. finally, for example, says what to do when the loop finally finishes. Most types of clauses (except finally) can appear more than once. With some clauses, where they appear makes a difference. With others, it doesn't.

Stepping clauses

for variable in expression

expression is evaluated and should return a list. variable is set to the first element of the list during the first iteration, the second element during the second iteration, and so on. When every element has been used, the loop stops. If the list is empty, no iteration occurs. A handy feature of for is that variable can be a list of variables, e.g., for (x y z) in l. The list must be a list of lists. On the first iteration, x will be the first element of the first list, y the second element of the first list, and z the third element. On the second iteration, x will be the first element of the second list, and so on.

for variable on expression

expression is evaluated and should return a list. variable is set to the list during the first iteration, the cdr of the list during the second iteration, the cddr during the third, and so on. When nil is reached, the loop stops. If the list is empty, no iteration occurs. variable can be a list of variables. See Steele, for examples, or experiment to see what happens.

for variable from start [<to | downto> end] [by increment]
        

This is like the standard iterative form in Fortran, Pascal, Basic, and so on. start, end, and increment, if given, should evaluate to integers. With from ... to, variable is start on the first iteration, start + increment on the second, and so on. increment is 1, if not given explicitly. If end is given, the iteration stops when variable is greater than or equal to end. With from ... downto, variable is start on the first iteration, start - increment on the second, and so on. increment must be given explicitly. The iteration stops when variable is less than or equal to end, if given. If no end is given, the loop goes forever, unless some other clause stops it, as in our first example. Some examples:

(loop for x from 1 to 3 do (print x))

prints 1, 2 and 3

(loop for x from 3 downto 1 by 2 do (print x))

prints 3 and 1

for variable = expression_1 [thenexpression_2]

expression_1 is evaluated, and variable is initialized to the result. On subsequent iterations, expression_2 is evaluated, and variable is assigned the result. If expression_2 is not given, then expression_1 is re-evaluated and assigned to variable. An example:

(loop for x = 1 then (1+ x) do (print x) until (> x 3))

prints 1, 2, 3, 4

Normal termination clauses

until expression

expression is evaluated on each iteration of the loop. When it becomes true, the loop is terminated and the finally expressions, if any, are executed. For example, the following returns 4, because 4 times 4 is 16:

(loop for i from 0
      until (= 16 (* i i))
      finally (return i))
while expression

Just like until, except that the loop is stopped if expression becomes false.

Premature termination clauses

always expression

expression is evaluated on each iteration of the loop. If it ever becomes false, the loop is terminated prematurely, nil is returned and the finally clause is not executed. If termination is not premature, then the finally clause is executed, with a default return value of t. See the description of finally for more examples. For example, the following returns t:

(loop for i from 0 to 10
      always (< i 11))

but this returns nil:

loop for i from 0 to 10
      always (evenp i)
never expression

Equivalent to always (not expression).

        thereis expression
        

Similar to never. If the expression evaluates to a non-nil value on some iteration, the loop is terminated, and the non-nil value is returned. An example:

(loop for x in '(a b c) thereis (member x '(e d c x)))

returns (c x)

Accumulation clauses

collect expression [into variable]

The expression is evaluated on each iteration of the loop and a list of the results, in order, is kept. If variable is given, the list is kept there. If variable is not given, two things happen. First, the list is kept internally. Second, the value of the internal list is returned when the loop finishes. For example, the following returns the list (1 2 3 4 5):

(loop for i from 1 to 5
      collect i)

Multiple collect clauses can add elements to the same list.

append expression [into variable]

Just like collect except that the results are appended together. For example, the following returns (1 a 3 c):

(loop for x in '((1 a) (2 b) (3 c) (4 d))
      when (oddp (first x))
            append x)

Note: you can collect and append into the same variable.

Unconditional Execution clause

do [expression]

The expressions can be any non-atomic Lisp forms. They are evaluated, in order, on each iteration of the loop.

Conditional Execution clauses

if expression clause [else else-clause]

expression is evaluated on each iteration of the loop. When it is true, clause is executed. If it is not, then else-clause is executed, if present. Note that these are clauses not expressions. clause and else-clause can be any execution (conditional or unconditional) or accumulation clause.

(loop for x in '(1 2 3 4)
      if (evenp x)
            do (print (list 'even x))
            else (print (list 'odd x)))
when expression clause

Just like if, but may be clearer when there is no else clause.

unless expression clause

Just like when except that clause is executed when expression is false.

Finally clause

finally [expression]

The expressions can be any non-atomic Lisp form. They are evaluated, in order, after the loop has finished iterating. If you want to return a particular value, the last expression should have the form (return value). For example, the following would print the numbers from 1 to 5 in the main body of the loop, then the final clause would return 6.

(loop for i from 1 to 5
      do (print i)
      finally (return i))

Note: if the loop is terminated prematurely, the final clauses are not executed. For example, the following terminates the loop prematurely with the value 2, and the string is never printed.

(loop for i from 1 to 5
      when (evenp i)
            do (return i)
      finally (print "You won't see this"))

Likewise, the following terminates the loop prematurely and returns nil.

(loop for i from 1 to 5
      always (oddp i)
      finally (print "You won't see this"))