388 lines
30 KiB
HTML
388 lines
30 KiB
HTML
|
<HTML><HEAD><TITLE>Macros: Standard Control Constructs</TITLE><LINK REL="stylesheet" TYPE="text/css" HREF="style.css"/></HEAD><BODY><DIV CLASS="copyright">Copyright © 2003-2005, Peter Seibel</DIV><H1>7. Macros: Standard Control Constructs</H1><P>While many of the ideas that originated in Lisp, from the conditional
|
|||
|
expression to garbage collection, have been incorporated into other
|
|||
|
languages, the one language feature that continues to set Common Lisp
|
|||
|
apart is its macro system. Unfortunately, the word <I>macro</I> describes
|
|||
|
a lot of things in computing to which Common Lisp's macros bear only a
|
|||
|
vague and metaphorical similarity. This causes no end of
|
|||
|
misunderstanding when Lispers try to explain to non-Lispers what a
|
|||
|
great feature macros are.<SUP>1</SUP> To understand
|
|||
|
Lisp's macros, you really need to come at them fresh, without
|
|||
|
preconceptions based on other things that also happen to be called
|
|||
|
macros. So let's start our discussion of Lisp's macros by taking a
|
|||
|
step back and looking at various ways languages support extensibility.</P><P>All programmers should be used to the idea that the definition of a
|
|||
|
language can include a standard library of functionality that's
|
|||
|
implemented in terms of the "core" language--functionality that could
|
|||
|
have been implemented by any programmer on top of the language if it
|
|||
|
hadn't been defined as part of the standard library. C's standard
|
|||
|
library, for instance, can be implemented almost entirely in portable
|
|||
|
C. Similarly, most of the ever-growing set of classes and interfaces
|
|||
|
that ship with Java's standard Java Development Kit (JDK) are written
|
|||
|
in "pure" Java.</P><P>One advantage of defining languages in terms of a core plus a
|
|||
|
standard library is it makes them easier to understand and implement.
|
|||
|
But the real benefit is in terms of expressiveness--since much of
|
|||
|
what you think of as "the language" is really just a library--the
|
|||
|
language is easy to extend. If C doesn't have a function to do some
|
|||
|
thing or another that you need, you can write that function, and now
|
|||
|
you have a slightly richer version of C. Similarly, in a language
|
|||
|
such as Java or Smalltalk where almost all the interesting parts of
|
|||
|
the "language" are defined in terms of classes, by defining new
|
|||
|
classes you extend the language, making it more suited for writing
|
|||
|
programs to do whatever it is you're trying to do. </P><P>While Common Lisp supports both these methods of extending the
|
|||
|
language, macros give Common Lisp yet another way. As I discussed
|
|||
|
briefly in Chapter 4, each macro defines its own syntax, determining
|
|||
|
how the s-expressions it's passed are turned into Lisp forms. With
|
|||
|
macros as part of the core language it's possible to build new
|
|||
|
syntax--control constructs such as <CODE><B>WHEN</B></CODE>, <CODE><B>DOLIST</B></CODE>, and
|
|||
|
<CODE><B>LOOP</B></CODE> as well as definitional forms such as <CODE><B>DEFUN</B></CODE> and
|
|||
|
<CODE><B>DEFPARAMETER</B></CODE>--as part of the "standard library" rather than
|
|||
|
having to hardwire them into the core. This has implications for how
|
|||
|
the language itself is implemented, but as a Lisp programmer you'll
|
|||
|
care more that it gives you another way to extend the language,
|
|||
|
making it a better language for expressing solutions to your
|
|||
|
particular programming problems.</P><P>Now, it may seem that the benefits of having another way to extend
|
|||
|
the language would be easy to recognize. But for some reason a lot of
|
|||
|
folks who haven't actually used Lisp macros--folks who think nothing
|
|||
|
of spending their days creating new functional abstractions or
|
|||
|
defining hierarchies of classes to solve their programming
|
|||
|
problems--get spooked by the idea of being able to define new
|
|||
|
syntactic abstractions. The most common cause of macrophobia seems to
|
|||
|
be bad experiences with other "macro" systems. Simple fear of the
|
|||
|
unknown no doubt plays a role, too. To avoid triggering any
|
|||
|
macrophobic reactions, I'll ease into the subject by discussing
|
|||
|
several of the standard control-construct macros defined by Common
|
|||
|
Lisp. These are some of the things that, if Lisp didn't have macros,
|
|||
|
would have to be built into the language core. When you use them, you
|
|||
|
don't have to care that they're implemented as macros, but they
|
|||
|
provide a good example of some of the things you can do with
|
|||
|
macros.<SUP>2</SUP> In the
|
|||
|
next chapter, I'll show you how you can define your own macros. </P><A NAME="when-and-unless"><H2>WHEN and UNLESS</H2></A><P>As you've already seen, the most basic form of conditional
|
|||
|
execution--if <I>x</I>, do <I>y</I>; otherwise do <I>z</I>--is provided by the
|
|||
|
<CODE><B>IF</B></CODE> special operator, which has this basic form:</P><PRE>(if <I>condition</I> <I>then-form</I> [<I>else-form</I>])</PRE><P>The <I>condition</I> is evaluated and, if its value is non-<CODE><B>NIL</B></CODE>, the
|
|||
|
<I>then-form</I> is evaluated and the resulting value returned.
|
|||
|
Otherwise, the <I>else-form</I>, if any, is evaluated and its value
|
|||
|
returned. If <I>condition</I> is <CODE><B>NIL</B></CODE> and there's no <I>else-form</I>,
|
|||
|
then the <CODE><B>IF</B></CODE> returns <CODE><B>NIL</B></CODE>.</P><PRE>(if (> 2 3) "Yup" "Nope") ==> "Nope"
|
|||
|
(if (> 2 3) "Yup") ==> NIL
|
|||
|
(if (> 3 2) "Yup" "Nope") ==> "Yup"</PRE><P>However, <CODE><B>IF</B></CODE> isn't actually such a great syntactic construct
|
|||
|
because the <I>then-form</I> and <I>else-form</I> are each restricted to
|
|||
|
being a single Lisp form. This means if you want to perform a
|
|||
|
sequence of actions in either clause, you need to wrap them in some
|
|||
|
other syntax. For instance, suppose in the middle of a spam-filtering
|
|||
|
program you wanted to both file a message as spam and update the spam
|
|||
|
database when a message is spam. You can't write this: </P><PRE>(if (spam-p current-message)
|
|||
|
(file-in-spam-folder current-message)
|
|||
|
(update-spam-database current-message))</PRE><P>because the call to <CODE>update-spam-database</CODE> will be treated as
|
|||
|
the else clause, not as part of the then clause. Another special
|
|||
|
operator, <CODE><B>PROGN</B></CODE>, executes any number of forms in order and
|
|||
|
returns the value of the last form. So you could get the desired
|
|||
|
behavior by writing the following:</P><PRE>(if (spam-p current-message)
|
|||
|
(progn
|
|||
|
(file-in-spam-folder current-message)
|
|||
|
(update-spam-database current-message)))</PRE><P>That's not too horrible. But given the number of times you'll likely
|
|||
|
have to use this idiom, it's not hard to imagine that you'd get tired
|
|||
|
of it after a while. "Why," you might ask yourself, "doesn't Lisp
|
|||
|
provide a way to say what I really want, namely, 'When <I>x</I> is true,
|
|||
|
do this, that, and the other thing'?" In other words, after a while
|
|||
|
you'd notice the pattern of an <CODE><B>IF</B></CODE> plus a <CODE><B>PROGN</B></CODE> and wish for
|
|||
|
a way to abstract away the details rather than writing them out every
|
|||
|
time.</P><P>This is exactly what macros provide. In this case, Common Lisp comes
|
|||
|
with a standard macro, <CODE><B>WHEN</B></CODE>, which lets you write this: </P><PRE>(when (spam-p current-message)
|
|||
|
(file-in-spam-folder current-message)
|
|||
|
(update-spam-database current-message))</PRE><P>But if it wasn't built into the standard library, you could define
|
|||
|
<CODE><B>WHEN</B></CODE> yourself with a macro such as this, using the backquote
|
|||
|
notation I discussed in Chapter 3:<SUP>3</SUP></P><PRE>(defmacro when (condition &rest body)
|
|||
|
`(if ,condition (progn ,@body)))</PRE><P>A counterpart to the <CODE><B>WHEN</B></CODE> macro is <CODE><B>UNLESS</B></CODE>, which reverses
|
|||
|
the condition, evaluating its body forms only if the condition is
|
|||
|
false. In other words: </P><PRE>(defmacro unless (condition &rest body)
|
|||
|
`(if (not ,condition) (progn ,@body)))</PRE><P>Admittedly, these are pretty trivial macros. There's no deep black
|
|||
|
magic here; they just abstract away a few language-level bookkeeping
|
|||
|
details, allowing you to express your true intent a bit more clearly.
|
|||
|
But their very triviality makes an important point: because the macro
|
|||
|
system is built right into the language, you can write trivial macros
|
|||
|
like <CODE><B>WHEN</B></CODE> and <CODE><B>UNLESS</B></CODE> that give you small but real gains in
|
|||
|
clarity that are then multiplied by the thousands of times you use
|
|||
|
them. In Chapters 24, 26, and 31 you'll see how macros can also be
|
|||
|
used on a larger scale, creating whole domain-specific embedded
|
|||
|
languages. But first let's finish our discussion of the standard
|
|||
|
control-construct macros. </P><A NAME="cond"><H2>COND</H2></A><P>Another time raw <CODE><B>IF</B></CODE> expressions can get ugly is when you have a
|
|||
|
multibranch conditional: if <I>a</I> do <I>x</I>, else if <I>b</I> do <I>y</I>;
|
|||
|
else do <I>z</I>. There's no logical problem writing such a chain of
|
|||
|
conditional expressions with just <CODE><B>IF</B></CODE>, but it's not pretty.</P><PRE>(if a
|
|||
|
(do-x)
|
|||
|
(if b
|
|||
|
(do-y)
|
|||
|
(do-z)))</PRE><P>And it would be even worse if you needed to include multiple forms in
|
|||
|
the then clauses, requiring <CODE><B>PROGN</B></CODE>s. So, not surprisingly, Common
|
|||
|
Lisp provides a macro for expressing multibranch conditionals:
|
|||
|
<CODE><B>COND</B></CODE>. This is the basic skeleton:</P><PRE>(cond
|
|||
|
(<I>test-1</I> <I>form</I>*)
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
(<I>test-N</I> <I>form</I>*))</PRE><P>Each element of the body represents one branch of the conditional and
|
|||
|
consists of a list containing a condition form and zero or more forms
|
|||
|
to be evaluated if that branch is chosen. The conditions are
|
|||
|
evaluated in the order the branches appear in the body until one of
|
|||
|
them evaluates to true. At that point, the remaining forms in that
|
|||
|
branch are evaluated, and the value of the last form in the branch is
|
|||
|
returned as the value of the <CODE><B>COND</B></CODE> as a whole. If the branch
|
|||
|
contains no forms after the condition, the value of the condition is
|
|||
|
returned instead. By convention, the branch representing the final
|
|||
|
else clause in an if/else-if chain is written with a condition of
|
|||
|
<CODE><B>T</B></CODE>. Any non-<CODE><B>NIL</B></CODE> value will work, but a <CODE><B>T</B></CODE> serves as a
|
|||
|
useful landmark when reading the code. Thus, you can write the
|
|||
|
previous nested <CODE><B>IF</B></CODE> expression using <CODE><B>COND</B></CODE> like this: </P><PRE>(cond (a (do-x))
|
|||
|
(b (do-y))
|
|||
|
(t (do-z)))</PRE><A NAME="and-or-and-not"><H2>AND, OR, and NOT</H2></A><P>When writing the conditions in <CODE><B>IF</B></CODE>, <CODE><B>WHEN</B></CODE>, <CODE><B>UNLESS</B></CODE>, and
|
|||
|
<CODE><B>COND</B></CODE> forms, three operators that will come in handy are the
|
|||
|
boolean logic operators, <CODE><B>AND</B></CODE>, <CODE><B>OR</B></CODE>, and <CODE><B>NOT</B></CODE>.</P><P><CODE><B>NOT</B></CODE> is a function so strictly speaking doesn't belong in this
|
|||
|
chapter, but it's closely tied to <CODE><B>AND</B></CODE> and <CODE><B>OR</B></CODE>. It takes a
|
|||
|
single argument and inverts its truth value, returning <CODE><B>T</B></CODE> if the
|
|||
|
argument is <CODE><B>NIL</B></CODE> and <CODE><B>NIL</B></CODE> otherwise.</P><P><CODE><B>AND</B></CODE> and <CODE><B>OR</B></CODE>, however, are macros. They implement logical
|
|||
|
conjunction and disjunction of any number of subforms and are defined
|
|||
|
as macros so they can <I>short-circuit</I>. That is, they evaluate only
|
|||
|
as many of their subforms--in left-to-right order--as necessary to
|
|||
|
determine the overall truth value. Thus, <CODE><B>AND</B></CODE> stops and returns
|
|||
|
<CODE><B>NIL</B></CODE> as soon as one of its subforms evaluates to <CODE><B>NIL</B></CODE>. If all
|
|||
|
the subforms evaluate to non-<CODE><B>NIL</B></CODE>, it returns the value of the
|
|||
|
last subform. <CODE><B>OR</B></CODE>, on the other hand, stops as soon as one of its
|
|||
|
subforms evaluates to non-<CODE><B>NIL</B></CODE> and returns the resulting value. If
|
|||
|
none of the subforms evaluate to true, <CODE><B>OR</B></CODE> returns <CODE><B>NIL</B></CODE>. Here
|
|||
|
are some examples:</P><PRE>(not nil) ==> T
|
|||
|
(not (= 1 1)) ==> NIL
|
|||
|
(and (= 1 2) (= 3 3)) ==> NIL
|
|||
|
(or (= 1 2) (= 3 3)) ==> T</PRE><A NAME="looping"><H2>Looping</H2></A><P>Control constructs are the other main kind of looping constructs.
|
|||
|
Common Lisp's looping facilities are--in addition to being quite
|
|||
|
powerful and flexible--an interesting lesson in the
|
|||
|
have-your-cake-and-eat-it-too style of programming that macros
|
|||
|
provide.</P><P>As it turns out, none of Lisp's 25 special operators directly support
|
|||
|
structured looping. All of Lisp's looping control constructs are
|
|||
|
macros built on top of a pair of special operators that provide a
|
|||
|
primitive goto facility.<SUP>4</SUP> Like many good abstractions,
|
|||
|
syntactic or otherwise, Lisp's looping macros are built as a set of
|
|||
|
layered abstractions starting from the base provided by those two
|
|||
|
special operators.</P><P>At the bottom (leaving aside the special operators) is a very general
|
|||
|
looping construct, <CODE><B>DO</B></CODE>. While very powerful, <CODE><B>DO</B></CODE> suffers, as
|
|||
|
do many general-purpose abstractions, from being overkill for simple
|
|||
|
situations. So Lisp also provides two other macros, <CODE><B>DOLIST</B></CODE> and
|
|||
|
<CODE><B>DOTIMES</B></CODE>, that are less flexible than <CODE><B>DO</B></CODE> but provide
|
|||
|
convenient support for the common cases of looping over the elements
|
|||
|
of a list and counting loops. While an implementation can implement
|
|||
|
these macros however it wants, they're typically implemented as
|
|||
|
macros that expand into an equivalent <CODE><B>DO</B></CODE> loop. Thus, <CODE><B>DO</B></CODE>
|
|||
|
provides a basic structured looping construct on top of the
|
|||
|
underlying primitives provided by Common Lisp's special operators,
|
|||
|
and <CODE><B>DOLIST</B></CODE> and <CODE><B>DOTIMES</B></CODE> provide two easier-to-use, if less
|
|||
|
general, constructs. And, as you'll see in the next chapter, you can
|
|||
|
build your own looping constructs on top of <CODE><B>DO</B></CODE> for situations
|
|||
|
where <CODE><B>DOLIST</B></CODE> and <CODE><B>DOTIMES</B></CODE> don't meet your needs.</P><P>Finally, the <CODE><B>LOOP</B></CODE> macro provides a full-blown mini-language for
|
|||
|
expressing looping constructs in a non-Lispy, English-like (or at
|
|||
|
least Algol-like) language. Some Lisp hackers love <CODE><B>LOOP</B></CODE>; others
|
|||
|
hate it. <CODE><B>LOOP</B></CODE>'s fans like it because it provides a concise way
|
|||
|
to express certain commonly needed looping constructs. Its detractors
|
|||
|
dislike it because it's not Lispy enough. But whichever side one
|
|||
|
comes down on, it's a remarkable example of the power of macros to
|
|||
|
add new constructs to the language. </P><A NAME="dolist-and-dotimes"><H2>DOLIST and DOTIMES</H2></A><P>I'll start with the easy-to-use <CODE><B>DOLIST</B></CODE> and <CODE><B>DOTIMES</B></CODE> macros.</P><P><CODE><B>DOLIST</B></CODE> loops across the items of a list, executing the loop body
|
|||
|
with a variable holding the successive items of the
|
|||
|
list.<SUP>5</SUP> This is the
|
|||
|
basic skeleton (leaving out some of the more esoteric options):</P><PRE>(dolist (<I>var</I> <I>list-form</I>)
|
|||
|
<I>body-form</I>*)</PRE><P>When the loop starts, the <I>list-form</I> is evaluated once to produce
|
|||
|
a list. Then the body of the loop is evaluated once for each item in
|
|||
|
the list with the variable <I>var</I> holding the value of the item. For
|
|||
|
instance:</P><PRE>CL-USER> (dolist (x '(1 2 3)) (print x))
|
|||
|
1
|
|||
|
2
|
|||
|
3
|
|||
|
NIL</PRE><P>Used this way, the <CODE><B>DOLIST</B></CODE> form as a whole evaluates to <CODE><B>NIL</B></CODE>.</P><P>If you want to break out of a <CODE><B>DOLIST</B></CODE> loop before the end of the
|
|||
|
list, you can use <CODE><B>RETURN</B></CODE>.</P><PRE>CL-USER> (dolist (x '(1 2 3)) (print x) (if (evenp x) (return)))
|
|||
|
1
|
|||
|
2
|
|||
|
NIL</PRE><P><CODE><B>DOTIMES</B></CODE> is the high-level looping construct for counting loops.
|
|||
|
The basic template is much the same as <CODE><B>DOLIST</B></CODE>'s. </P><PRE>(dotimes (<I>var</I> <I>count-form</I>)
|
|||
|
<I>body-form</I>*)</PRE><P>The <I>count-form</I> must evaluate to an integer. Each time through the
|
|||
|
loop <I>var</I> holds successive integers from 0 to one less than that
|
|||
|
number. For instance:</P><PRE>CL-USER> (dotimes (i 4) (print i))
|
|||
|
0
|
|||
|
1
|
|||
|
2
|
|||
|
3
|
|||
|
NIL</PRE><P>As with <CODE><B>DOLIST</B></CODE>, you can use <CODE><B>RETURN</B></CODE> to break out of the loop
|
|||
|
early.</P><P>Because the body of both <CODE><B>DOLIST</B></CODE> and <CODE><B>DOTIMES</B></CODE> loops can
|
|||
|
contain any kind of expressions, you can also nest loops. For
|
|||
|
example, to print out the times tables from <CODE>1 <20> 1 = 1</CODE> to
|
|||
|
<CODE>20 <20> 20 = 400</CODE>, you can write this pair of nested <CODE><B>DOTIMES</B></CODE>
|
|||
|
loops:</P><PRE>(dotimes (x 20)
|
|||
|
(dotimes (y 20)
|
|||
|
(format t "~3d " (* (1+ x) (1+ y))))
|
|||
|
(format t "~%"))</PRE><A NAME="do"><H2>DO</H2></A><P>While <CODE><B>DOLIST</B></CODE> and <CODE><B>DOTIMES</B></CODE> are convenient and easy to use,
|
|||
|
they aren't flexible enough to use for all loops. For instance, what
|
|||
|
if you want to step multiple variables in parallel? Or use an
|
|||
|
arbitrary expression to test for the end of the loop? If neither
|
|||
|
<CODE><B>DOLIST</B></CODE> nor <CODE><B>DOTIMES</B></CODE> meet your needs, you still have access
|
|||
|
to the more general <CODE><B>DO</B></CODE> loop.</P><P>Where <CODE><B>DOLIST</B></CODE> and <CODE><B>DOTIMES</B></CODE> provide only one loop variable,
|
|||
|
<CODE><B>DO</B></CODE> lets you bind any number of variables and gives you complete
|
|||
|
control over how they change on each step through the loop. You also
|
|||
|
get to define the test that determines when to end the loop and can
|
|||
|
provide a form to evaluate at the end of the loop to generate a
|
|||
|
return value for the <CODE><B>DO</B></CODE> expression as a whole. The basic
|
|||
|
template looks like this: </P><PRE>(do (<I>variable-definition</I>*)
|
|||
|
(<I>end-test-form</I> <I>result-form</I>*)
|
|||
|
<I>statement</I>*)</PRE><P>Each <I>variable-definition</I> introduces a variable that will be in
|
|||
|
scope in the body of the loop. The full form of a single variable
|
|||
|
definition is a list containing three elements.</P><PRE>(<I>var</I> <I>init-form</I> <I>step-form</I>)</PRE><P>The <I>init-form</I> will be evaluated at the beginning of the loop and
|
|||
|
the resulting values bound to the variable <I>var</I>. Before each
|
|||
|
subsequent iteration of the loop, the <I>step-form</I> will be evaluated
|
|||
|
and the new value assigned to <I>var</I>. The <I>step-form</I> is optional;
|
|||
|
if it's left out, the variable will keep its value from iteration to
|
|||
|
iteration unless you explicitly assign it a new value in the loop
|
|||
|
body. As with the variable definitions in a <CODE><B>LET</B></CODE>, if the
|
|||
|
<I>init-form</I> is left out, the variable is bound to <CODE><B>NIL</B></CODE>. Also as
|
|||
|
with <CODE><B>LET</B></CODE>, you can use a plain variable name as shorthand for a
|
|||
|
list containing just the name.</P><P>At the beginning of each iteration, after all the loop variables have
|
|||
|
been given their new values, the <I>end-test-form</I> is evaluated. As
|
|||
|
long as it evaluates to <CODE><B>NIL</B></CODE>, the iteration proceeds, evaluating
|
|||
|
the <I>statements</I> in order.</P><P>When the <I>end-test-form</I> evaluates to true, the <I>result-forms</I>
|
|||
|
are evaluated, and the value of the last result form is returned as
|
|||
|
the value of the <CODE><B>DO</B></CODE> expression.</P><P>At each step of the iteration the step forms for all the variables
|
|||
|
are evaluated before assigning any of the values to the variables.
|
|||
|
This means you can refer to any of the other loop variables in the
|
|||
|
step forms.<SUP>6</SUP> That is, in a loop like this: </P><PRE>(do ((n 0 (1+ n))
|
|||
|
(cur 0 next)
|
|||
|
(next 1 (+ cur next)))
|
|||
|
((= 10 n) cur))</PRE><P>the step forms <CODE>(1+ n)</CODE>, <CODE>next</CODE>, and <CODE>(+ cur next)</CODE>
|
|||
|
are all evaluated using the old values of <CODE>n</CODE>, <CODE>cur</CODE>, and
|
|||
|
<CODE>next</CODE>. Only after all the step forms have been evaluated are
|
|||
|
the variables given their new values. (Mathematically inclined
|
|||
|
readers may notice that this is a particularly efficient way of
|
|||
|
computing the eleventh Fibonacci number.)</P><P>This example also illustrates another characteristic of
|
|||
|
<CODE><B>DO</B></CODE>--because you can step multiple variables, you often don't
|
|||
|
need a body at all. Other times, you may leave out the result form,
|
|||
|
particularly if you're just using the loop as a control construct.
|
|||
|
This flexibility, however, is the reason that <CODE><B>DO</B></CODE> expressions can
|
|||
|
be a bit cryptic. Where exactly do all the parentheses go? The best
|
|||
|
way to understand a <CODE><B>DO</B></CODE> expression is to keep in mind the basic
|
|||
|
template.</P><PRE><B>(</B>do <B>(</B><I>variable-definition</I>*<B>)</B>
|
|||
|
<B>(</B><I>end-test-form</I> <I>result-form</I>*<B>)</B>
|
|||
|
<I>statement</I>*<B>)</B></PRE><P>The six parentheses in that template are the only ones required by
|
|||
|
the <CODE><B>DO</B></CODE> itself. You need one pair to enclose the variable
|
|||
|
declarations, one pair to enclose the end test and result forms, and
|
|||
|
one pair to enclose the whole expression. Other forms within the
|
|||
|
<CODE><B>DO</B></CODE> may require their own parentheses--variable definitions are
|
|||
|
usually lists, for instance. And the test form is often a function
|
|||
|
call. But the skeleton of a <CODE><B>DO</B></CODE> loop will always be the same.
|
|||
|
Here are some example <CODE><B>DO</B></CODE> loops with the skeleton in bold: </P><PRE><B>(</B>do <B>(</B>(i 0 (1+ i))<B>)</B>
|
|||
|
<B>(</B>(>= i 4)<B>)</B>
|
|||
|
(print i)<B>)</B></PRE><P>Notice that the result form has been omitted. This is, however, not a
|
|||
|
particularly idiomatic use of <CODE><B>DO</B></CODE>, as this loop is much more
|
|||
|
simply written using <CODE><B>DOTIMES</B></CODE>.<SUP>7</SUP></P><PRE>(dotimes (i 4) (print i))</PRE><P>As another example, here's the bodiless Fibonacci-computing loop:</P><PRE><B>(</B>do <B>(</B>(n 0 (1+ n))
|
|||
|
(cur 0 next)
|
|||
|
(next 1 (+ cur next))<B>)</B>
|
|||
|
<B>(</B>(= 10 n) cur<B>))</B></PRE><P>Finally, the next loop demonstrates a <CODE><B>DO</B></CODE> loop that binds no
|
|||
|
variables. It loops while the current time is less than the value of
|
|||
|
a global variable, printing "Waiting" once a minute. Note that even
|
|||
|
with no loop variables, you still need the empty variables list.</P><PRE><B>(</B>do <B>()</B>
|
|||
|
<B>(</B>(> (get-universal-time) *some-future-date*)<B>)</B>
|
|||
|
(format t "Waiting~%")
|
|||
|
(sleep 60)<B>)</B> </PRE><A NAME="the-mighty-loop"><H2>The Mighty LOOP</H2></A><P>For the simple cases you have <CODE><B>DOLIST</B></CODE> and <CODE><B>DOTIMES</B></CODE>. And if
|
|||
|
they don't suit your needs, you can fall back on the completely
|
|||
|
general <CODE><B>DO</B></CODE>. What more could you want?</P><P>Well, it turns out a handful of looping idioms come up over and over
|
|||
|
again, such as looping over various data structures: lists, vectors,
|
|||
|
hash tables, and packages. Or accumulating values in various ways
|
|||
|
while looping: collecting, counting, summing, minimizing, or
|
|||
|
maximizing. If you need a loop to do one of these things (or several
|
|||
|
at the same time), the <CODE><B>LOOP</B></CODE> macro may give you an easier way to
|
|||
|
express it.</P><P>The <CODE><B>LOOP</B></CODE> macro actually comes in two flavors--<I>simple</I> and
|
|||
|
<I>extended</I>. The simple version is as simple as can be--an infinite
|
|||
|
loop that doesn't bind any variables. The skeleton looks like this: </P><PRE>(loop
|
|||
|
<I>body-form</I>*)</PRE><P>The forms in body are evaluated each time through the loop, which
|
|||
|
will iterate forever unless you use <CODE><B>RETURN</B></CODE> to break out. For
|
|||
|
example, you could write the previous <CODE><B>DO</B></CODE> loop with a simple
|
|||
|
<CODE><B>LOOP</B></CODE>.</P><PRE>(loop
|
|||
|
(when (> (get-universal-time) *some-future-date*)
|
|||
|
(return))
|
|||
|
(format t "Waiting~%")
|
|||
|
(sleep 60))</PRE><P>The extended <CODE><B>LOOP</B></CODE> is quite a different beast. It's distinguished
|
|||
|
by the use of certain <I>loop keywords</I> that implement a
|
|||
|
special-purpose language for expressing looping idioms. It's worth
|
|||
|
noting that not all Lispers love the extended <CODE><B>LOOP</B></CODE> language. At
|
|||
|
least one of Common Lisp's original designers hated it. <CODE><B>LOOP</B></CODE>'s
|
|||
|
detractors complain that its syntax is totally un-Lispy (in other
|
|||
|
words, not enough parentheses). <CODE><B>LOOP</B></CODE>'s fans counter that that's
|
|||
|
the point: complicated looping constructs are hard enough to
|
|||
|
understand without wrapping them up in <CODE><B>DO</B></CODE>'s cryptic syntax. It's
|
|||
|
better, they say, to have a slightly more verbose syntax that gives
|
|||
|
you some clues what the heck is going on. </P><P>For instance, here's an idiomatic <CODE><B>DO</B></CODE> loop that collects the
|
|||
|
numbers from 1 to 10 into a list:</P><PRE>(do ((nums nil) (i 1 (1+ i)))
|
|||
|
((> i 10) (nreverse nums))
|
|||
|
(push i nums)) ==> (1 2 3 4 5 6 7 8 9 10)</PRE><P>A seasoned Lisper won't have any trouble understanding that
|
|||
|
code--it's just a matter of understanding the basic form of a <CODE><B>DO</B></CODE>
|
|||
|
loop and recognizing the <CODE><B>PUSH</B></CODE>/<CODE><B>NREVERSE</B></CODE> idiom for building
|
|||
|
up a list. But it's not exactly transparent. The <CODE><B>LOOP</B></CODE> version,
|
|||
|
on the other hand, is almost understandable as an English sentence.</P><PRE>(loop for i from 1 to 10 collecting i) ==> (1 2 3 4 5 6 7 8 9 10)</PRE><P>The following are some more examples of simple uses of <CODE><B>LOOP</B></CODE>.
|
|||
|
This sums the first ten squares:</P><PRE>(loop for x from 1 to 10 summing (expt x 2)) ==> 385</PRE><P>This counts the number of vowels in a string:</P><PRE>(loop for x across "the quick brown fox jumps over the lazy dog"
|
|||
|
counting (find x "aeiou")) ==> 11</PRE><P>This computes the eleventh Fibonacci number, similar to the <CODE><B>DO</B></CODE>
|
|||
|
loop used earlier: </P><PRE>(loop for i below 10
|
|||
|
and a = 0 then b
|
|||
|
and b = 1 then (+ b a)
|
|||
|
finally (return a))</PRE><P>The symbols <CODE>across</CODE>, <CODE>and</CODE>, <CODE>below</CODE>,
|
|||
|
<CODE>collecting</CODE>, <CODE>counting</CODE>, <CODE>finally</CODE>, <CODE>for</CODE>,
|
|||
|
<CODE>from</CODE>, <CODE>summing</CODE>, <CODE>then</CODE>, and <CODE>to</CODE> are some of
|
|||
|
the loop keywords whose presence identifies these as instances of the
|
|||
|
extended <CODE><B>LOOP</B></CODE>. <SUP>8</SUP></P><P>I'll save the details of <CODE><B>LOOP</B></CODE> for Chapter 22, but it's worth
|
|||
|
noting here as another example of the way macros can be used to
|
|||
|
extend the base language. While <CODE><B>LOOP</B></CODE> provides its own language
|
|||
|
for expressing looping constructs, it doesn't cut you off from the
|
|||
|
rest of Lisp. The loop keywords are parsed according to loop's
|
|||
|
grammar, but the rest of the code in a <CODE><B>LOOP</B></CODE> is regular Lisp
|
|||
|
code. </P><P>And it's worth pointing out one more time that while the <CODE><B>LOOP</B></CODE>
|
|||
|
macro is quite a bit more complicated than macros such as <CODE><B>WHEN</B></CODE>
|
|||
|
or <CODE><B>UNLESS</B></CODE>, it <I>is</I> just another macro. If it hadn't been
|
|||
|
included in the standard library, you could implement it yourself or
|
|||
|
get a third-party library that does.</P><P>With that I'll conclude our tour of the basic control-construct
|
|||
|
macros. Now you're ready to take a closer look at how to define your
|
|||
|
own macros.
|
|||
|
</P><HR/><DIV CLASS="notes"><P><SUP>1</SUP>To see what this misunderstanding looks
|
|||
|
like, find any longish Usenet thread cross-posted between
|
|||
|
comp.lang.lisp and any other comp.lang.* group with <I>macro</I> in the
|
|||
|
subject. A rough paraphrase goes like this:</P><P>Lispnik: "Lisp is the best because of its macros!";</P><P>Othernik: "You think Lisp is good <I>because of</I> macros?! But macros
|
|||
|
are horrible and evil; Lisp must be horrible and evil."</P><P><SUP>2</SUP>Another important class of language constructs that are
|
|||
|
defined using macros are all the definitional constructs such as
|
|||
|
<CODE><B>DEFUN</B></CODE>, <CODE><B>DEFPARAMETER</B></CODE>, <CODE><B>DEFVAR</B></CODE>, and others. In Chapter 24
|
|||
|
you'll define your own definitional macros that will allow you to
|
|||
|
concisely write code for reading and writing binary data.</P><P><SUP>3</SUP>You can't actually feed this
|
|||
|
definition to Lisp because it's illegal to redefine names in the
|
|||
|
<CODE>COMMON-LISP</CODE> package where <CODE><B>WHEN</B></CODE> comes from. If you really
|
|||
|
want to try writing such a macro, you'd need to change the name to
|
|||
|
something else, such as <CODE>my-when</CODE>.</P><P><SUP>4</SUP>The special operators, if you must
|
|||
|
know, are <CODE><B>TAGBODY</B></CODE> and <CODE><B>GO</B></CODE>. There's no need to discuss them
|
|||
|
now, but I'll cover them in Chapter 20.</P><P><SUP>5</SUP><CODE><B>DOLIST</B></CODE> is similar to Perl's <CODE>foreach</CODE> or
|
|||
|
Python's <CODE>for</CODE>. Java added a similar kind of loop construct with
|
|||
|
the "enhanced" <CODE>for</CODE> loop in Java 1.5, as part of JSR-201.
|
|||
|
Notice what a difference macros make. A Lisp programmer who notices a
|
|||
|
common pattern in their code can write a macro to give themselves a
|
|||
|
source-level abstraction of that pattern. A Java programmer who
|
|||
|
notices the same pattern has to convince Sun that this particular
|
|||
|
abstraction is worth adding to the language. Then Sun has to publish
|
|||
|
a JSR and convene an industry-wide "expert group" to hash everything
|
|||
|
out. That process--according to Sun--takes an average of 18 months.
|
|||
|
After that, the compiler writers all have to go upgrade their
|
|||
|
compilers to support the new feature. And even once the Java
|
|||
|
programmer's favorite compiler supports the new version of Java, they
|
|||
|
probably <I>still</I> can't use the new feature until they're allowed to
|
|||
|
break source compatibility with older versions of Java. So an
|
|||
|
annoyance that Common Lisp programmers can resolve for themselves
|
|||
|
within five minutes plagues Java programmers for years.</P><P><SUP>6</SUP>A variant of <CODE><B>DO</B></CODE>, <CODE><B>DO*</B></CODE>, assigns each
|
|||
|
variable its value before evaluating the step form for subsequent
|
|||
|
variables. For more details, consult your favorite Common Lisp
|
|||
|
reference.</P><P><SUP>7</SUP>The <CODE><B>DOTIMES</B></CODE> is also
|
|||
|
preferred because the macro expansion will likely include
|
|||
|
declarations that allow the compiler to generate more efficient
|
|||
|
code.</P><P><SUP>8</SUP><I>Loop keywords</I> is a bit of a misnomer
|
|||
|
since they aren't keyword symbols. In fact, <CODE><B>LOOP</B></CODE> doesn't care
|
|||
|
what package the symbols are from. When the <CODE><B>LOOP</B></CODE> macro parses
|
|||
|
its body, it considers any appropriately named symbols equivalent.
|
|||
|
You could even use true keywords if you wanted--<CODE>:for</CODE>,
|
|||
|
<CODE>:across</CODE>, and so on--because they also have the correct name.
|
|||
|
But most folks just use plain symbols. Because the loop keywords are
|
|||
|
used only as syntactic markers, it doesn't matter if they're used for
|
|||
|
other purposes--as function or variable names.</P></DIV></BODY></HTML>
|