1
0
Fork 0
cl-sites/gigamonkeys.com/book/loop-for-black-belts.html

469 lines
40 KiB
HTML
Raw Normal View History

2023-10-25 11:23:21 +02:00
<HTML><HEAD><TITLE>LOOP for Black Belts</TITLE><LINK REL="stylesheet" TYPE="text/css" HREF="style.css"/></HEAD><BODY><DIV CLASS="copyright">Copyright &copy; 2003-2005, Peter Seibel</DIV><H1>22. LOOP for Black Belts</H1><P>In Chapter 7 I briefly discussed the extended <CODE><B>LOOP</B></CODE> macro. As I
mentioned then, <CODE><B>LOOP</B></CODE> provides what is essentially a
special-purpose language just for writing iteration constructs.</P><P>This might seem like a lot of bother--inventing a whole language just
for writing loops. But if you think about the ways loops are used in
programs, it actually makes a fair bit of sense. Any program of any
size at all will contain quite a number of loops. And while they
won't all be the same, they won't all be unique either; patterns will
emerge, particularly if you include the code immediately preceding
and following the loops--patterns of how things are set up for the
loop, patterns in what gets done in the loop proper, and patterns in
what gets done after the loop. The <CODE><B>LOOP</B></CODE> language captures these
patterns so you can express them directly.</P><P>The <CODE><B>LOOP</B></CODE> macro has a lot of parts--one of the main complaints of
<CODE><B>LOOP</B></CODE>'s detractors is that it's too complex. In this chapter,
I'll tackle <CODE><B>LOOP</B></CODE> head on, giving you a systematic tour of the
various parts and how they fit together.</P><A NAME="the-parts-of-a-loop"><H2>The Parts of a LOOP</H2></A><P>You can do the following in a <CODE><B>LOOP</B></CODE>:</P><UL><LI>Step variables numerically and over various data structures</LI><LI>Collect, count, sum, minimize, and maximize values seen while looping</LI><LI>Execute arbitrary Lisp expressions</LI><LI>Decide when to terminate the loop</LI><LI>Conditionally do any of these</LI></UL><P>Additionally, <CODE><B>LOOP</B></CODE> provides syntax for the following:</P><UL><LI>Creating local variables for use within the loop</LI><LI>Specifying arbitrary Lisp expressions to run before and after
the loop proper</LI></UL><P>The basic structure of a <CODE><B>LOOP</B></CODE> is a set of clauses, each of which
begins with a <I>loop keyword</I>.<SUP>1</SUP> How each clause is parsed by the
<CODE><B>LOOP</B></CODE> macro depends on the keyword. Some of the main keywords,
which you saw in Chapter 7, are <CODE>for</CODE>, <CODE>collecting</CODE>,
<CODE>summing</CODE>, <CODE>counting</CODE>, <CODE>do</CODE>, and <CODE>finally</CODE>.</P><A NAME="iteration-control"><H2>Iteration Control</H2></A><P>Most of the so-called iteration control clauses start with the loop
keyword <CODE>for</CODE>, or its synonym <CODE>as</CODE>,<SUP>2</SUP>
followed by the name of a variable. What follows after the variable
name depends on the type of <CODE>for</CODE> clause.</P><P>The subclauses of a <CODE>for</CODE> clause can iterate over the following:</P><UL><LI>Ranges of numbers, up or down, by specified intervals</LI><LI>The individual items of a list</LI><LI>The cons cells that make up a list</LI><LI>The elements of a vector, including subtypes such as strings and
bit vectors</LI><LI>The pairs of a hash table</LI><LI>The symbols in a package</LI><LI>The results of repeatedly evaluating a given form</LI></UL><P>A single loop can have multiple <CODE>for</CODE> clauses with each clause
naming its own variable. When a loop has multiple <CODE>for</CODE> clauses,
the loop terminates as soon as any <CODE>for</CODE> clause reaches its end
condition. For instance, the following loop:</P><PRE>(loop
for item in list
for i from 1 to 10
do (something))</PRE><P>will iterate at most ten times but may stop sooner if <CODE>list</CODE>
contains fewer than ten items.</P><A NAME="counting-loops"><H2>Counting Loops</H2></A><P>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 <I>prepositional phrases</I> after the <CODE>for</CODE>
(or <CODE>as</CODE>): the <I>from where</I> phrase, the <I>to where</I> phrase, and
the <I>by how much</I> phrase.</P><P>The <I>from where</I> phrase specifies the initial value of the clause's
variable. It consists of one of the prepositions <CODE>from</CODE>,
<CODE>downfrom</CODE>, or <CODE>upfrom</CODE> followed by a form, which supplies
the initial value (a number).</P><P>The <I>to where</I> phrase specifies a stopping point for the loop and
consists of one of the prepositions <CODE>to</CODE>, <CODE>upto</CODE>,
<CODE>below</CODE>, <CODE>downto</CODE>, or <CODE>above</CODE> followed by a form,
which supplies the stopping point. With <CODE>upto</CODE> and
<CODE>downto</CODE>, the loop body will be terminated (without executing
the body again) when the variable passes the stopping point; with
<CODE>below</CODE> and <CODE>above</CODE>, it stops one iteration earlier.The
<I>by how much</I> phrase consists of the prepositions <CODE>by</CODE> 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.</P><P>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 <I>from
where</I> value, so you must specify one with either <CODE>from</CODE> or
<CODE>downfrom</CODE>. So, the following:</P><PRE>(loop for i upto 10 collect i)</PRE><P>collects the first eleven integers (zero to ten), but the behavior of
this:</P><PRE>(loop for i downto -10 collect i) ; wrong</PRE><P>is undefined. Instead, you need to write this:</P><PRE>(loop for i from 0 downto -10 collect i)</PRE><P>Also note that because <CODE><B>LOOP</B></CODE> 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:</P><PRE>(loop for i from 10 to 20 ...) </PRE><P>works fine since the default is incremental stepping. But this:</P><PRE>(loop for i from 20 to 10 ...) </PRE><P>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 <CODE>i</CODE> is
already greater than ten. Instead, you must write this:</P><PRE>(loop for i from 20 downto 10 ...)</PRE><P>or this:</P><PRE>(loop for i downfrom 20 to 10 ...)</PRE><P>Finally, if you just want a loop that repeats a certain number of
times, you can replace a clause of the following form:</P><PRE>for i from 1 to <I>number-form</I></PRE><P>with a <CODE>repeat</CODE> clause like this:</P><PRE>repeat <I>number-form</I></PRE><P>These clauses are identical in effect except the <CODE>repeat</CODE> clause
doesn't create an explicit loop variable.</P><A NAME="looping-over-collections-and-packages"><H2>Looping Over Collections and Packages</H2></A><P>The <CODE>for</CODE> clauses for iterating over lists are much simpler than
the arithmetic clauses. They support only two prepositional phrases,
<CODE>in</CODE> and <CODE>on</CODE>.</P><P>A phrase of this form:</P><PRE>for <I>var</I> in <I>list-form</I></PRE><P>steps <I>var</I> over all the elements of the list produced by
evaluating <I>list-form</I>. </P><PRE>(loop for i in (list 10 20 30 40) collect i) ==&gt; (10 20 30 40)</PRE><P>Occasionally this clause is supplemented with a <CODE>by</CODE> phrase,
which specifies a function to use to move down the list. The default
is <CODE><B>CDR</B></CODE> but can be any function that takes a list and returns a
sublist. For instance, you could collect every other element of a
list with a loop like this:</P><PRE>(loop for i in (list 10 20 30 40) by #'cddr collect i) ==&gt; (10 30)</PRE><P>An <CODE>on</CODE> prepositional phrase is used to step <I>var</I> over the
cons cells that make up a list.</P><PRE>(loop for x on (list 10 20 30) collect x) ==&gt; ((10 20 30) (20 30) (30))</PRE><P>This phrase too can take a <CODE>by</CODE> preposition:</P><PRE>(loop for x on (list 10 20 30 40) by #'cddr collect x) ==&gt; ((10 20 30 40) (30 40))</PRE><P>Looping over the elements of a vector (which includes strings and bit
vectors) is similar to looping over the elements of a list except the
preposition <CODE>across</CODE> is used instead of <CODE>in</CODE>.<SUP>3</SUP> For instance:</P><PRE>(loop for x across &quot;abcd&quot; collect x) ==&gt; (#\a #\b #\c #\d)</PRE><P>Iterating over a hash table or package is slightly more complicated
because hash tables and packages have different sets of values you
might want to iterate over--the keys or values in a hash table and
the different kinds of symbols in a package. Both kinds of iteration
follow the same pattern. The basic pattern looks like this:</P><PRE>(loop for <I>var</I> being the <I>things</I> in <I>hash-or-package</I> ...)</PRE><P>For hash tables, the possible values for <I>things</I> are
<CODE>hash-keys</CODE> and <CODE>hash-values</CODE>, which cause <CODE>var</CODE> to be
bound to successive values of either the keys or the values of the
hash table. The <I>hash-or-package</I> form is evaluated once to
produce a value, which must be a hash table.</P><P>To iterate over a package, <I>things</I> can be <CODE>symbols</CODE>,
<CODE>present-symbols</CODE>, and <CODE>external-symbols</CODE>, which cause
<I>var</I> to be bound to each of the symbols accessible in a package,
each of the symbols present in a package (in other words, interned or
imported into that package), or each of the symbols that have been
exported from the package. The <I>hash-or-package</I> form is evaluated
to produce the name of a package, which is looked up as if by
<CODE><B>FIND-PACKAGE</B></CODE> or a package object. Synonyms are also available
for parts of the <CODE>for</CODE> clause. In place of <CODE>the</CODE>, you can
use <CODE>each</CODE>; you can use <CODE>of</CODE> instead of <CODE>in</CODE>; and you
can write the <I>things</I> in the singular (for example,
<CODE>hash-key</CODE> or <CODE>symbol</CODE>).</P><P>Finally, since you'll often want both the keys and the values when
iterating over a hash table, the hash table clauses support a
<CODE>using</CODE> subclause at the end of the hash table clause.</P><PRE>(loop for k being the hash-keys in h using (hash-value v) ...)
(loop for v being the hash-values in h using (hash-key k) ...)</PRE><P>Both of these loops will bind <CODE>k</CODE> to each key in the hash table
and <CODE>v</CODE> to the corresponding value. Note that the first element
of the <CODE>using</CODE> subclause must be in the singular
form.<SUP>4</SUP></P><A NAME="equals-then-iteration"><H2>Equals-Then Iteration</H2></A><P>If none of the other <CODE>for</CODE> clauses supports exactly the form of
variable stepping you need, you can take complete control over
stepping with an <I>equals-then</I> clause. This clause is similar to
the binding clauses in a <CODE><B>DO</B></CODE> loop but cast in a more Algolish
syntax. The template is as follows:</P><PRE>(loop for <I>var</I> = <I>initial-value-form</I> [ then <I>step-form</I> ] ...)</PRE><P>As usual, <I>var</I> is the name of the variable to be stepped. Its
initial value is obtained by evaluating <I>initial-value-form</I> once
before the first iteration. In each subsequent iteration,
<I>step-form</I> is evaluated, and its value becomes the new value of
<I>var</I>. With no <CODE>then</CODE> part to the clause, the
<I>initial-value-form</I> is reevaluated on each iteration to provide
the new value. Note that this is different from a <CODE><B>DO</B></CODE> binding
clause with no step form.</P><P>The <I>step-form</I> can refer to other loop variables, including
variables created by other <CODE>for</CODE> clauses later in the loop. For
instance:</P><PRE>(loop repeat 5
for x = 0 then y
for y = 1 then (+ x y)
collect y) ==&gt; (1 2 4 8 16)</PRE><P>However, note that each <CODE>for</CODE> clause is evaluated separately in
the order it appears. So in the previous loop, on the second
iteration <CODE>x</CODE> is set to the value of <CODE>y</CODE> before <CODE>y</CODE>
changes (in other words, <CODE>1</CODE>). But <CODE>y</CODE> is then set to the
sum of its old value (still <CODE>1</CODE>) and the new value of <CODE>x</CODE>.
If the order of the <CODE>for</CODE> clauses is reversed, the results
change.</P><PRE>(loop repeat 5
for y = 1 then (+ x y)
for x = 0 then y
collect y) ==&gt; (1 1 2 4 8)</PRE><P>Often, however, you'll want the step forms for multiple variables to
be evaluated before any of the variables is given its new value
(similar to how <CODE><B>DO</B></CODE> steps its variables). In that case, you can
join multiple <CODE>for</CODE> clauses by replacing all but the first
<CODE>for</CODE> with <CODE>and</CODE>. You saw this formulation already in the
<CODE><B>LOOP</B></CODE> version of the Fibonacci computation in Chapter 7. Here's
another variant, based on the two previous examples:</P><PRE>(loop repeat 5
for x = 0 then y
and y = 1 then (+ x y)
collect y) ==&gt; (1 1 2 3 5)</PRE><A NAME="local-variables"><H2>Local Variables</H2></A><P>While the main variables needed within a loop are usually declared
implicitly in <CODE>for</CODE> clauses, sometimes you'll need auxiliary
variables, which you can declare with <CODE>with</CODE> clauses.</P><PRE>with <I>var</I> [ = <I>value-form</I> ]</PRE><P>The name <I>var</I> becomes the name of a local variable that will cease
to exist when the loop finishes. If the <CODE>with</CODE> clause contains
an <CODE>=</CODE> <CODE>value-form</CODE> part, the variable will be initialized,
before the first iteration of the loop, to the value of
<I>value-form</I>.</P><P>Multiple <CODE>with</CODE> clauses can appear in a loop; each clause is
evaluated independently in the order it appears and the value is
assigned before proceeding to the next clause, allowing later
variables to depend on the value of already declared variables.
Mutually independent variables can be declared in one <CODE>with</CODE>
clause with an <CODE>and</CODE> between each declaration.</P><A NAME="destructuring-variables"><H2>Destructuring Variables</H2></A><P>One handy feature of <CODE><B>LOOP</B></CODE> I haven't mentioned yet is the ability
to destructure list values assigned to loop variables. This lets you
take apart the value of lists that would otherwise be assigned to a
loop variable, similar to the way <CODE><B>DESTRUCTURING-BIND</B></CODE> works but a
bit less elaborate. Basically, you can replace any loop variable in a
<CODE>for</CODE> or <CODE>with</CODE> clause with a tree of symbols, and the list
value that would have been assigned to the simple variable will
instead be destructured into variables named by the symbols in the
tree. A simple example looks like this:</P><PRE>CL-USER&gt; (loop for (a b) in '((1 2) (3 4) (5 6))
do (format t &quot;a: ~a; b: ~a~%&quot; a b))
a: 1; b: 2
a: 3; b: 4
a: 5; b: 6
NIL</PRE><P>The tree can also include dotted lists, in which case the name after
the dot acts like a <CODE><B>&amp;rest</B></CODE> parameter, being bound to a list
containing any remaining elements of the list. This is particularly
handy with <CODE>for</CODE>/<CODE>on</CODE> loops since the value is always a
list. For instance, this <CODE><B>LOOP</B></CODE> (which I used in Chapter 18 to
emit a comma-delimited list):</P><PRE>(loop for cons on list
do (format t &quot;~a&quot; (car cons))
when (cdr cons) do (format t &quot;, &quot;))</PRE><P>could also be written like this:</P><PRE>(loop for (item . rest) on list
do (format t &quot;~a&quot; item)
when rest do (format t &quot;, &quot;))</PRE><P>If you want to ignore a value in the destructured list, you can use
<CODE><B>NIL</B></CODE> in place of a variable name.</P><PRE>(loop for (a nil) in '((1 2) (3 4) (5 6)) collect a) ==&gt; (1 3 5)</PRE><P>If the destructuring list contains more variables than there are
values in the list, the extra variables are set to <CODE><B>NIL</B></CODE>, making
all the variables essentially like <CODE><B>&amp;optional</B></CODE> parameters. There
isn't, however, any equivalent to <CODE><B>&amp;key</B></CODE> parameters.</P><A NAME="value-accumulation"><H2>Value Accumulation</H2></A><P>The value accumulation clauses are perhaps the most powerful part of
<CODE><B>LOOP</B></CODE>. While the iteration control clauses provide a concise
syntax for expressing the basic mechanics of looping, they aren't
dramatically different from the equivalent mechanisms provided by
<CODE><B>DO</B></CODE>, <CODE><B>DOLIST</B></CODE>, and <CODE><B>DOTIMES</B></CODE>.</P><P>The value accumulation clauses, on the other hand, provide a concise
notation for a handful of common loop idioms having to do with
accumulating values while looping. Each accumulation clause starts
with a verb and follows this pattern:</P><PRE><I>verb</I> <I>form</I> [ into <I>var</I> ]</PRE><P>Each time through the loop, an accumulation clause evaluates <I>form</I>
and saves the value in a manner determined by the <I>verb</I>. With an
<CODE>into</CODE> subclause, the value is saved into the variable named by
<I>var</I>. The variable is local to the loop, as if it'd been declared
in a <CODE>with</CODE> clause. With no <CODE>into</CODE> subclause, the
accumulation clause instead accumulates a default value for the whole
loop expression.</P><P>The possible verbs are <CODE>collect</CODE>, <CODE>append</CODE>, <CODE>nconc</CODE>,
<CODE>count</CODE>, <CODE>sum</CODE>, <CODE>maximize</CODE>, and <CODE>minimize</CODE>. Also
available as synonyms are the present participle forms:
<CODE>collecting</CODE>, <CODE>appending</CODE>, <CODE>nconcing</CODE>,
<CODE>counting</CODE>, <CODE>summing</CODE>, <CODE>maximizing</CODE>, and
<CODE>minimizing</CODE>.</P><P>A <CODE>collect</CODE> clause builds up a list containing all the values of
<I>form</I> in the order they're seen. This is a particularly useful
construct because the code you'd have to write to collect a list in
order as efficiently as <CODE><B>LOOP</B></CODE> does is more painful than you'd
normally write by hand.<SUP>5</SUP> Related to <CODE>collect</CODE> are the verbs <CODE>append</CODE> and
<CODE>nconc</CODE>. These verbs also accumulate values into a list, but they
join the values, which must be lists, into a single list as if by the
functions <CODE><B>APPEND</B></CODE> or <CODE><B>NCONC</B></CODE>. <SUP>6</SUP></P><P>The remaining accumulation clauses are used to accumulate numeric
values. The verb <CODE>count</CODE> counts the number of times <I>form</I> is
true, <CODE>sum</CODE> collects a running total of the values of <I>form</I>,
<CODE>maximize</CODE> collects the largest value seen for <I>form</I>, and
<CODE>minimize</CODE> collects the smallest. For instance, suppose you
define a variable <CODE>*random*</CODE> that contains a list of random
numbers.</P><PRE>(defparameter *random* (loop repeat 100 collect (random 10000)))</PRE><P>Then the following loop will return a list containing various summary
information about the numbers:</P><PRE>(loop for i in *random*
counting (evenp i) into evens
counting (oddp i) into odds
summing i into total
maximizing i into max
minimizing i into min
finally (return (list min max total evens odds)))</PRE><A NAME="unconditional-execution"><H2>Unconditional Execution</H2></A><P>As useful as the value accumulation constructs are, <CODE><B>LOOP</B></CODE> wouldn't
be a very good general-purpose iteration facility if there wasn't a
way to execute arbitrary Lisp code in the loop body.</P><P>The simplest way to execute arbitrary code within a loop body is with
a <CODE>do</CODE> clause. Compared to the clauses I've described so far,
with their prepositions and subclauses, <CODE>do</CODE> is a model of
Yodaesque simplicity.<SUP>7</SUP> A <CODE>do</CODE> clause
consists of the word <CODE>do</CODE> (or <CODE>doing</CODE>) followed by one or
more Lisp forms that are all evaluated when the <CODE>do</CODE> clause is.
The <CODE>do</CODE> clause ends at the closing parenthesis of the loop or
the next loop keyword.</P><P>For instance, to print the numbers from one to ten, you could write
this:</P><PRE>(loop for i from 1 to 10 do (print i))</PRE><P>Another, more dramatic, form of immediate execution is a <CODE>return</CODE>
clause. This clause consists of the word <CODE>return</CODE> followed by a
single Lisp form, which is evaluated, with the resulting value
immediately returned as the value of the loop.</P><P>You can also break out of a loop in a <CODE>do</CODE> clause using any of
Lisp's normal control flow operators, such as <CODE><B>RETURN</B></CODE> and
<CODE><B>RETURN-FROM</B></CODE>. Note that a <CODE>return</CODE> clause always returns
from the immediately enclosing <CODE><B>LOOP</B></CODE> expression, while a
<CODE><B>RETURN</B></CODE> or <CODE><B>RETURN-FROM</B></CODE> in a <CODE>do</CODE> clause can return from
any enclosing expression. For instance, compare the following:</P><PRE>(block outer
(loop for i from 0 return 100) ; 100 returned from LOOP
(print &quot;This will print&quot;)
200) ==&gt; 200</PRE><P>to this:</P><PRE>(block outer
(loop for i from 0 do (return-from outer 100)) ; 100 returned from BLOCK
(print &quot;This won't print&quot;)
200) ==&gt; 100</PRE><P>The <CODE>do</CODE> and <CODE>return</CODE> clauses are collectively called the
<I>unconditional execution</I> clauses.</P><A NAME="conditional-execution"><H2>Conditional Execution</H2></A><P>Because a <CODE>do</CODE> clause can contain arbitrary Lisp forms, you can
use any Lisp expressions you want, including control constructs such
as <CODE><B>IF</B></CODE> and <CODE><B>WHEN</B></CODE>. So, the following is one way to write a
loop that prints only the even numbers between one and ten:</P><PRE>(loop for i from 1 to 10 do (when (evenp i) (print i)))</PRE><P>However, sometimes you'll want conditional control at the level of
loop clauses. For instance, suppose you wanted to sum only the even
numbers between one and ten using a <CODE>summing</CODE> clause. You
couldn't write such a loop with a <CODE>do</CODE> clause because there'd be
no way to &quot;call&quot; the <CODE>sum i</CODE> in the middle of a regular Lisp
form. In cases like this, you need to use one of <CODE><B>LOOP</B></CODE>'s own
conditional expressions like this:</P><PRE>(loop for i from 1 to 10 when (evenp i) sum i) ==&gt; 30</PRE><P><CODE><B>LOOP</B></CODE> provides three conditional constructs, and they all follow
this basic pattern:</P><PRE><I>conditional</I> <I>test-form</I> <I>loop-clause</I></PRE><P>The <I>conditional</I> can be <CODE>if</CODE>, <CODE>when</CODE>, or <CODE>unless</CODE>.
The <I>test-form</I> is any regular Lisp form, and <I>loop-clause</I> can
be a value accumulation clause (<CODE>count</CODE><I>, </I><CODE>collect</CODE><I>,
and so on), an unconditional execution</I> clause, or another
conditional execution clause. Multiple loop clauses can be attached
to a single conditional by joining them with <CODE>and</CODE>.</P><P>As an extra bit of syntactic sugar, within the first loop clause,
after the test form, you can use the variable <CODE>it</CODE> to refer to
the value returned by the test form. For instance, the following loop
collects the non-<CODE><B>NIL</B></CODE> values found in <CODE>some-hash</CODE> when
looking up the keys in <CODE>some-list</CODE>:</P><PRE>(loop for key in some-list when (gethash key some-hash) collect it)</PRE><P>A conditional clause is executed each time through the loop. An
<CODE>if</CODE> or <CODE>when</CODE> clause executes its <I>loop-clause</I> if
<I>test-form</I> evaluates to true. An <CODE>unless</CODE> reverses the test,
executing <I>loop-clause</I> only when <I>test-form</I> is <CODE><B>NIL</B></CODE>. Unlike
their Common Lisp namesakes, <CODE><B>LOOP</B></CODE>'s <CODE>if</CODE> and <CODE>when</CODE>
are merely synonyms--there's no difference in their behavior.</P><P>All three conditional clauses can also take an <CODE>else</CODE> branch,
which is followed by another loop clause or multiple clauses joined by
<CODE>and</CODE>. When conditional clauses are nested, the set of clauses
connected to an inner conditional clause can be closed with the word
<CODE>end</CODE>. The <CODE>end</CODE> is optional when not needed to disambiguate
a nested conditional--the end of a conditional clause will be inferred
from the end of the loop or the start of another clause not joined by
<CODE>and</CODE>.</P><P>The following rather silly loop demonstrates the various forms of
<CODE><B>LOOP</B></CODE> conditionals. The <CODE>update-analysis</CODE> function will be
called each time through the loop with the latest values of the
various variables accumulated by the clauses within the conditionals.</P><PRE>(loop for i from 1 to 100
if (evenp i)
minimize i into min-even and
maximize i into max-even and
unless (zerop (mod i 4))
sum i into even-not-fours-total
end
and sum i into even-total
else
minimize i into min-odd and
maximize i into max-odd and
when (zerop (mod i 5))
sum i into fives-total
end
and sum i into odd-total
do (update-analysis min-even
max-even
min-odd
max-odd
even-total
odd-total
fives-total
even-not-fours-total))</PRE><A NAME="setting-up-and-tearing-down"><H2>Setting Up and Tearing Down</H2></A><P>One of the key insights the designers of the <CODE><B>LOOP</B></CODE> language had
about actual loops &quot;in the wild&quot; is that the loop proper is often
preceded by a bit of code to set things up and then followed by some
more code that does something with the values computed by the loop. A
trivial example, in Perl,<SUP>8</SUP> might look like this:</P><PRE>my $evens_sum = 0;
my $odds_sum = 0;
foreach my $i (@list_of_numbers) {
if ($i % 2) {
$odds_sum += $i;
} else {
$evens_sum += $i;
}
}
if ($evens_sum &gt; $odds_sum) {
print &quot;Sum of evens greater\n&quot;;
} else {
print &quot;Sum of odds greater\n&quot;;
}</PRE><P>The loop proper in this code is the <CODE>foreach</CODE> statement. But the
<CODE>foreach</CODE> loop doesn't stand on its own: the code in the loop
body refers to variables declared in the two lines before the
loop.<SUP>9</SUP> And
the work the loop does is all for naught without the <CODE>if</CODE>
statement after the loop that actually reports the results. In Common
Lisp, of course, the <CODE><B>LOOP</B></CODE> construct is an expression that
returns a value, so there's even more often a need to do something
after the loop proper, namely, generate the return value.</P><P>So, said the <CODE><B>LOOP</B></CODE> designers, let's give a way to include the
code that's really part of the loop in the loop itself. Thus,
<CODE><B>LOOP</B></CODE> provides two keywords, <CODE>initially</CODE> and <CODE>finally</CODE>,
that introduce code to be run outside the loop's main body.</P><P>After the <CODE>initially</CODE> or <CODE>finally</CODE>, these clauses consist
of all the Lisp forms up to the start of the next loop clause or the
end of the loop. All the <CODE>initially</CODE> forms are combined into a
single <I>prologue</I>, which runs once, immediately after all the local
loop variables are initialized and before the body of the loop. The
<CODE>finally</CODE> forms are similarly combined into a <I>epilogue</I> to be
run after the last iteration of the loop body. Both the prologue and
epilogue code can refer to local loop variables.</P><P>The prologue is always run, even if the loop body iterates zero
times. The loop can return without running the epilogue if any of the
following happens:</P><UL><LI>A <CODE>return</CODE> clause executes.</LI><LI><CODE><B>RETURN</B></CODE> , <CODE><B>RETURN-FROM</B></CODE>, or another transfer of control
construct is called from within a Lisp form within the body.<SUP>10</SUP></LI><LI>The loop is terminated by an <CODE>always</CODE>, <CODE>never</CODE>, or
<CODE>thereis</CODE> clause, as I'll discuss in the next section.</LI></UL><P>Within the epilogue code, <CODE><B>RETURN</B></CODE> or <CODE><B>RETURN-FROM</B></CODE> can be used
to explicitly provide a return value for the loop. Such an explicit
return value will take precedence over any value that might otherwise
be provided by an accumulation or termination test clause.</P><P>To allow <CODE><B>RETURN-FROM</B></CODE> to be used to return from a specific loop
(useful when nesting <CODE><B>LOOP</B></CODE> expressions), you can name a <CODE><B>LOOP</B></CODE>
with the loop keyword <CODE>named</CODE>. If a <CODE>named</CODE> clause appears
in a loop, it must be the first clause. For a simple example, assume
<CODE>lists</CODE> is a list of lists and you want to find an item that
matches some criteria in one of those nested lists. You could find it
with a pair of nested loops like this:</P><PRE>(loop named outer for list in lists do
(loop for item in list do
(if (what-i-am-looking-for-p item)
(return-from outer item))))</PRE><A NAME="termination-tests"><H2>Termination Tests</H2></A><P>While the <CODE>for</CODE> and <CODE>repeat</CODE> clauses provide the basic
infrastructure for controlling the number of iterations, sometimes
you'll need to break out of a loop early. You've already seen how a
<CODE>return</CODE> clause or a <CODE><B>RETURN</B></CODE> or <CODE><B>RETURN-FROM</B></CODE> within a
<CODE>do</CODE> clause can immediately terminate the loop; but just as
there are common patterns for accumulating values, there are also
common patterns for deciding when it's time to bail on a loop. These
patterns are supported in <CODE><B>LOOP</B></CODE> by the termination clauses,
<CODE>while</CODE>, <CODE>until</CODE>, <CODE>always</CODE>, <CODE>never</CODE>, and
<CODE>thereis</CODE>. They all follow the same pattern.</P><PRE><I>loop-keyword</I> <I>test-form</I></PRE><P>All five evaluate <I>test-form</I> each time through the iteration and
decide, based on the resulting value, whether to terminate the loop.
They differ in what happens after they terminate the loop--if they
do--and how they decide.</P><P>The loop keywords <CODE>while</CODE> and <CODE>until</CODE> introduce the &quot;mild&quot;
termination clauses. When they decide to terminate the loop, control
passes to the epilogue, skipping the rest of the loop body. The
epilogue can then return a value or do whatever it wants to finish
the loop. A <CODE>while</CODE> clause terminates the loop the first time
the test form is false; <CODE>until</CODE>, conversely, stops it the first
time the test form is true.</P><P>Another form of mild termination is provided by the <CODE><B>LOOP-FINISH</B></CODE>
macro. This is a regular Lisp form, not a loop clause, so it can be
used anywhere within the Lisp forms of a <CODE>do</CODE> clause. It also
causes an immediate jump to the loop epilogue. It can be useful when
the decision to break out of the loop can't be easily condensed into a
single form that can be used with a <CODE>while</CODE> or <CODE>until</CODE>
clause.</P><P>The other three clauses--<CODE>always</CODE>, <CODE>never</CODE>, and
<CODE>thereis</CODE>--terminate the loop with extreme prejudice; they
immediately return from the loop, skipping not only any subsequent
loop clauses but also the epilogue. They also provide a default value
for the loop even when they don't cause the loop to terminate.
However, if the loop is <I>not</I> terminated by one of these termination
tests, the epilogue is run and can return a value other than the
default provided by the termination clauses.</P><P>Because these clauses provide their own return values, they can't be
combined with accumulation clauses unless the accumulation clause has
an <CODE>into</CODE> subclause. The compiler (or interpreter) should signal
an error at compile time if they are.The <CODE>always</CODE> and
<CODE>never</CODE> clauses return only boolean values, so they're most
useful when you need to use a loop expression as part of a predicate.
You can use <CODE>always</CODE> to check that the test form is true on
every iteration of the loop. Conversely, <CODE>never</CODE> tests that the
test form evaluates to <CODE><B>NIL</B></CODE> on every iteration. If the test form
fails (returning <CODE><B>NIL</B></CODE> in an <CODE>always</CODE> clause or non-<CODE><B>NIL</B></CODE>
in a <CODE>never</CODE> clause), the loop is immediately terminated,
returning <CODE><B>NIL</B></CODE>. If the loop runs to completion, the default value
of <CODE><B>T</B></CODE> is provided.</P><P>For instance, if you want to test that all the numbers in a list,
<CODE>numbers</CODE>, are even, you can write this:</P><PRE>(if (loop for n in numbers always (evenp n))
(print &quot;All numbers even.&quot;))</PRE><P>Equivalently you could write the following:</P><PRE>(if (loop for n in numbers never (oddp n))
(print &quot;All numbers even.&quot;))</PRE><P>A <CODE>thereis</CODE> clause is used to test whether the test form is
<I>ever</I> true. As soon as the test form returns a non-<CODE><B>NIL</B></CODE> value,
the loop is terminated, returning that value. If the loop runs to
completion, the <CODE>thereis</CODE> clause provides a default return value
of <CODE><B>NIL</B></CODE>.</P><PRE>(loop for char across &quot;abc123&quot; thereis (digit-char-p char)) ==&gt; 1
(loop for char across &quot;abcdef&quot; thereis (digit-char-p char)) ==&gt; NIL</PRE><A NAME="putting-it-all-together"><H2>Putting It All Together</H2></A><P>Now you've seen all the main features of the <CODE><B>LOOP</B></CODE> facility. You
can combine any of the clauses I've discussed as long as you abide by
the following rules:</P><UL><LI>The <CODE>named</CODE> clause, if any, must be the first clause.</LI><LI>After the <CODE>named</CODE> clause come all the <CODE>initially</CODE>,
<CODE>with</CODE>, <CODE>for</CODE>, and <CODE>repeat</CODE> clauses.</LI><LI>Then comes the body clauses: conditional and unconditional
execution, accumulation, and termination test.<SUP>11</SUP></LI><LI>End with any <CODE>finally</CODE> clauses.</LI></UL><P>The <CODE><B>LOOP</B></CODE> macro will expand into code that performs the following
actions:</P><UL><LI>Initializes all local loop variables as declared with
<CODE>with</CODE> or <CODE>for</CODE> clauses as well as those implicitly created
by accumulation clauses. The initial value forms are evaluated in the
order the clauses appear in the loop.</LI><LI>Execute the forms provided by any <CODE>initially</CODE> clauses--the
prologue--in the order they appear in the loop.</LI><LI>Iterate, executing the body of the loop as described in the next
paragraph.</LI><LI>Execute the forms provided by any <CODE>finally</CODE> clauses--the
epilogue--in the order they appear in the loop.</LI></UL><P>While the loop is iterating, the body is executed by first stepping
any iteration control variables and then executing any conditional or
unconditional execution, accumulation, or termination test clauses in
the order they appear in the loop code. If any of the clauses in the
loop body terminate the loop, the rest of the body is skipped and the
loop returns, possibly after running the epilogue.</P><P>And that's pretty much all there is to it.<SUP>12</SUP> You'll use
<CODE><B>LOOP</B></CODE> fairly often in the code later in this book, so it's worth
having some knowledge of it. Beyond that, it's up to you how much you
use it.</P><P>And with that, you're ready to dive into the practical chapters that
make up the rest of the book--up first, writing a spam filter.
</P><HR/><DIV CLASS="notes"><P><SUP>1</SUP>The term <I>loop keyword</I> is a
bit unfortunate, as loop keywords aren't keywords in the normal sense
of being symbols in the <CODE>KEYWORD</CODE> package. In fact, any symbol,
from any package, with the appropriate name will do; the <CODE><B>LOOP</B></CODE>
macro cares only about their names. Typically, though, they're
written with no package qualifier and are thus read (and interned as
necessary) in the current package.</P><P><SUP>2</SUP>Because one of the
goals of <CODE><B>LOOP</B></CODE> is to allow loop expressions to be written with a
quasi-English syntax, many of the keywords have synonyms that are
treated the same by <CODE><B>LOOP</B></CODE> but allow some freedom to express
things in slightly more idiomatic English for different contexts.</P><P><SUP>3</SUP>You may
wonder why <CODE><B>LOOP</B></CODE> can't figure out whether it's looping over a
list or a vector without needing different prepositions. This is
another consequence of <CODE><B>LOOP</B></CODE> being a macro: the value of the list
or vector won't be known until runtime, but <CODE><B>LOOP</B></CODE>, as a macro,
has to generate code at compile time. And <CODE><B>LOOP</B></CODE>'s designers
wanted it to generate extremely efficient code. To be able to
generate efficient code for looping across, say, a vector, it needs
to know at compile time that the value will be a vector at
runtime--thus, the different prepositions are needed.</P><P><SUP>4</SUP>Don't ask me why <CODE><B>LOOP</B></CODE>'s authors chickened out on the
no-parentheses style for the <CODE><B>using</B></CODE> subclause.</P><P><SUP>5</SUP>The trick is to keep ahold of the tail
of the list and add new cons cells by <CODE><B>SETF</B></CODE>ing the <CODE><B>CDR</B></CODE> of
the tail. A handwritten equivalent of the code generated by
<CODE>(loop for i upto 10 collect i)</CODE> would look like this:</P><PRE>(do ((list nil) (tail nil) (i 0 (1+ i)))
((&gt; i 10) list)
(let ((new (cons i nil)))
(if (null list)
(setf list new)
(setf (cdr tail) new))
(setf tail new)))</PRE><P>Of course you'll rarely, if ever, write code like that. You'll use
either <CODE><B>LOOP</B></CODE> or (if, for some reason, you don't want to use
<CODE><B>LOOP</B></CODE>) the standard <CODE><B>PUSH</B></CODE>/<CODE><B>NREVERSE</B></CODE> idiom for collecting
values.</P><P><SUP>6</SUP>Recall that <CODE><B>NCONC</B></CODE> is
the destructive version of <CODE><B>APPEND</B></CODE>--it's safe to use an
<CODE>nconc</CODE> clause only if the values you're collecting are fresh
lists that don't share any structure with other lists. For instance,
this is safe:</P><PRE>(loop for i upto 3 nconc (list i i)) ==&gt; (0 0 1 1 2 2 3 3)</PRE><P>But this will get you into trouble:</P><PRE>(loop for i on (list 1 2 3) nconc i) ==&gt; <I>undefined</I></PRE><P>The later will most likely get into an infinite loop as the various
parts of the list produced by (list 1 2 3) are destructively modified
to point to each other. But even that's not guaranteed--the behavior
is simply undefined.</P><P><SUP>7</SUP>&quot;No! Try not. Do . . . or do not. There is
no try.&quot; -- Yoda, <I>The Empire Strikes Back</I></P><P><SUP>8</SUP>I'm not picking on Perl here--this
example would look pretty much the same in any language that bases
its syntax on C's.</P><P><SUP>9</SUP>Perl would let you get away with not declaring those
variables if your program didn't <CODE>use strict</CODE>. But you should
<I>always</I> <CODE>use strict</CODE> in Perl. The equivalent code in Python,
Java, or C would always require the variables to be declared.</P><P><SUP>10</SUP>You
can cause a loop to finish normally, running the epilogue, from Lisp
code executed as part of the loop body with the local macro
<CODE><B>LOOP-FINISH</B></CODE>.</P><P><SUP>11</SUP>Some Common Lisp
implementations will let you get away with mixing body clauses and
<CODE>for</CODE> clauses, but that's strictly undefined, and some
implementations will reject such loops.</P><P><SUP>12</SUP>The one aspect of
<CODE><B>LOOP</B></CODE> I haven't touched on at all is the syntax for declaring the
types of loop variables. Of course, I haven't discussed type
declarations outside of <CODE><B>LOOP</B></CODE> either. I'll cover the general
topic a bit in Chapter 32. For information on how they work with
<CODE><B>LOOP</B></CODE>, consult your favorite Common Lisp reference.</P></DIV></BODY></HTML>