LOOP
head on, giving you a systematic tour of the various parts and how they fit together.
You can do the following in a LOOP
:
• Step variables numerically and over various data structures
• Collect, count, sum, minimize, and maximize values seen while looping
• Execute arbitrary Lisp expressions
• Decide when to terminate the loop
• Conditionally do any of these
Additionally, LOOP
provides syntax for the following:
• Creating local variables for use within the loop
• Specifying arbitrary Lisp expressions to run before and after the loop proper
The basic structure of a LOOP
is a set of clauses, each of which begins with a LOOP
macro depends on the keyword. Some of the main keywords, which you saw in Chapter 7, are for
, collecting
, summing
, counting
, do
, and finally
.
Most of the so-called iteration control clauses start with the loop keyword for
, or its synonym as
,[235] followed by the name of a variable. What follows after the variable name depends on the type of for
clause.
The subclauses of a for
clause can iterate over the following:
• Ranges of numbers, up or down, by specified intervals
• The individual items of a list
• The cons cells that make up a list
• The elements of a vector, including subtypes such as strings and bit vectors
• The pairs of a hash table
• The symbols in a package
• The results of repeatedly evaluating a given form
A single loop can have multiple for
clauses with each clause naming its own variable. When a loop has multiple for
clauses, the loop terminates as soon as any for
clause reaches its end condition. For instance, the following loop:
(loop
for item in list
for i from 1 to 10
do (something))
will iterate at most ten times but may stop sooner if list
contains fewer than ten items.
Arithmetic iteration clauses control the number of times the loop body will be executed by stepping a variable over a range of numbers, executing the body once per step. These clauses consist of from one to three of the following for
(or as
): the
The from
, downfrom
, or upfrom
followed by a form, which supplies the initial value (a number).
The to
, upto
, below
, downto
, or above
followed by a form, which supplies the stopping point. With upto
and downto
, the loop body will be terminated (without executing the body again) when the variable passes the stopping point; with below
and above
, it stops one iteration earlier.The by
and a form, which must evaluate to a positive number. The variable will be stepped (up or down, as determined by the other phrases) by this amount on each iteration or by one if it's omitted.
You must specify at least one of these prepositional phrases. The defaults are to start at zero, increment the variable by one at each iteration, and go forever or, more likely, until some other clause terminates the loop. You can modify any or all of these defaults by adding the appropriate prepositional phrases. The only wrinkle is that if you want decremental stepping, there's no default from
or downfrom
. So, the following:
(loop for i upto 10 collect i)
collects the first eleven integers (zero to ten), but the behavior of this:
(loop for i downto -10 collect i) ; wrong
is undefined. Instead, you need to write this:
(loop for i from 0 downto -10 collect i)
Also note that because LOOP
is a macro, which runs at compile time, it has to be able to determine the direction to step the variable based solely on the prepositions—not the values of the forms, which may not be known until runtime. So, the following:
(loop for i from 10 to 20 ...)
works fine since the default is incremental stepping. But this:
(loop for i from 20 to 10 ...)
won't know to count down from twenty to ten. Worse yet, it won't give you an error—it will just not execute the loop since i
is already greater than ten. Instead, you must write this:
(loop for i from 20 downto 10 ...)
or this:
(loop for i downfrom 20 to 10 ...)
Finally, if you just want a loop that repeats a certain number of times, you can replace a clause of the following form:
for i from 1 to
with a repeat
clause like this:
repeat
These clauses are identical in effect except the repeat
clause doesn't create an explicit loop variable.