469 lines
40 KiB
HTML
469 lines
40 KiB
HTML
|
<HTML><HEAD><TITLE>LOOP for Black Belts</TITLE><LINK REL="stylesheet" TYPE="text/css" HREF="style.css"/></HEAD><BODY><DIV CLASS="copyright">Copyright © 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) ==> (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) ==> (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) ==> ((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) ==> ((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 "abcd" collect x) ==> (#\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) ==> (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) ==> (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) ==> (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> (loop for (a b) in '((1 2) (3 4) (5 6))
|
||
|
do (format t "a: ~a; b: ~a~%" 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>&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 "~a" (car cons))
|
||
|
when (cdr cons) do (format t ", "))</PRE><P>could also be written like this:</P><PRE>(loop for (item . rest) on list
|
||
|
do (format t "~a" item)
|
||
|
when rest do (format t ", "))</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) ==> (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>&optional</B></CODE> parameters. There
|
||
|
isn't, however, any equivalent to <CODE><B>&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 "This will print")
|
||
|
200) ==> 200</PRE><P>to this:</P><PRE>(block outer
|
||
|
(loop for i from 0 do (return-from outer 100)) ; 100 returned from BLOCK
|
||
|
(print "This won't print")
|
||
|
200) ==> 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 "call" 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) ==> 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 "in the wild" 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 > $odds_sum) {
|
||
|
print "Sum of evens greater\n";
|
||
|
} else {
|
||
|
print "Sum of odds greater\n";
|
||
|
}</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 "mild"
|
||
|
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 "All numbers even."))</PRE><P>Equivalently you could write the following:</P><PRE>(if (loop for n in numbers never (oddp n))
|
||
|
(print "All numbers even."))</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 "abc123" thereis (digit-char-p char)) ==> 1
|
||
|
|
||
|
(loop for char across "abcdef" thereis (digit-char-p char)) ==> 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)))
|
||
|
((> 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)) ==> (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) ==> <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>"No! Try not. Do . . . or do not. There is
|
||
|
no try." -- 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>
|