about summary refs log tree commit diff stats
path: root/js/games/nluqo.github.io/~bh/v2ch12
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2023-08-23 07:52:19 -0400
committerelioat <elioat@tilde.institute>2023-08-23 07:52:19 -0400
commit562a9a52d599d9a05f871404050968a5fd282640 (patch)
tree7d3305c1252c043bfe246ccc7deff0056aa6b5ab /js/games/nluqo.github.io/~bh/v2ch12
parent5d012c6c011a9dedf7d0a098e456206244eb5a0f (diff)
downloadtour-562a9a52d599d9a05f871404050968a5fd282640.tar.gz
*
Diffstat (limited to 'js/games/nluqo.github.io/~bh/v2ch12')
-rw-r--r--js/games/nluqo.github.io/~bh/v2ch12/macro.html624
1 files changed, 624 insertions, 0 deletions
diff --git a/js/games/nluqo.github.io/~bh/v2ch12/macro.html b/js/games/nluqo.github.io/~bh/v2ch12/macro.html
new file mode 100644
index 0000000..dc40474
--- /dev/null
+++ b/js/games/nluqo.github.io/~bh/v2ch12/macro.html
@@ -0,0 +1,624 @@
+
+<P>
+<HTML>
+<HEAD>
+<TITLE>Computer Science Logo Style vol 2 ch 12: Macros</TITLE>
+</HEAD>
+<BODY>
+<CITE>Computer Science Logo Style</CITE> volume 2:
+<CITE>Advanced Techniques</CITE> 2/e Copyright (C) 1997 MIT
+<H1>Macros</H1>
+
+<TABLE width="100%"><TR><TD>
+<IMG SRC="../csls2.jpg" ALT="cover photo">
+<TD><TABLE>
+<TR><TD align="right"><CITE><A HREF="http://www.cs.berkeley.edu/~bh/">Brian
+Harvey</A><BR>University of California, Berkeley</CITE>
+<TR><TD align="right"><BR>
+<TR><TD align="right"><A HREF="../pdf/v2ch12.pdf">Download PDF version</A>
+<TR><TD align="right"><A HREF="../v2-toc2.html">Back to Table of Contents</A>
+<TR><TD align="right"><A HREF="../v2ch11/v2ch11.html"><STRONG>BACK</STRONG></A>
+chapter thread <A HREF="../v2ch13/v2ch13.html"><STRONG>NEXT</STRONG></A>
+<TR><TD align="right"><A HREF="https://mitpress.mit.edu/books/computer-science-logo-style-second-edition-volume-2">MIT
+Press web page for <CITE>Computer Science Logo Style</CITE></A>
+</TABLE></TABLE>
+
+<HR>
+
+<P>I mentioned that the versions of <CODE>for</CODE> and <CODE>foreach</CODE> shown in
+Chapter 10 don't work if their instruction templates include <CODE>stop</CODE> or
+<CODE>output</CODE> commands.  The problem is that we don't want, say, <CODE>foreach</CODE>
+to stop; we want the procedure that <EM>invoked</EM> <CODE>foreach</CODE> to stop.
+
+<P>What we need to fix this problem is a way for a subprocedure to <EM>make
+its caller</EM> carry out some action.  That is, we want something like <CODE>
+run</CODE>, but the given expression should be run in a different context.
+Berkeley Logo includes a mechanism, called <EM>macros,</EM> to allow
+this solution.  As I write this in 1996, no other version of Logo has
+macros, although this capability is commonly provided in most versions
+of Logo's cousin, the programming language Lisp.<SUP>*</SUP>
+
+<P><SMALL><BLOCKQUOTE><SMALL><SUP>*</SUP>Readers who are
+familiar with Lisp macros should take note that Logo macros do not
+prevent argument evaluation.</SMALL></BLOCKQUOTE></SMALL><P><H2><CODE>Localmake</CODE></H2>
+
+<P>Before we fix <CODE>for</CODE> and <CODE>foreach</CODE>, and even before I explain in
+detail what a macro is, I think it's best to start with a simple but
+practical example.  Throughout this book I've been using a command
+called <CODE>localmake</CODE> that creates a local variable and assigns it a
+value.  The instruction
+
+<P><PRE>localmake &quot;fred 87
+</PRE>
+
+<P>is an abbreviation for the two instructions
+
+<P><PRE>local &quot;fred
+make &quot;fred 87
+</PRE>
+
+<P>Any version of Logo will allow those two separate instructions.
+It's tempting to write a procedure combining them:
+
+<P><PRE>to localmake :name :value                   ;; wrong!
+local :name
+make :name :value
+end
+</PRE>
+
+<P>What's wrong with this solution?  If you're not sure, define <CODE>localmake</CODE>
+as above and try an example, like this:
+
+<P><PRE>to trial
+localmake &quot;fred 87
+print :fred
+end
+
+? <U>trial</U>
+fred has no value  in trial
+[print :fred]
+</PRE>
+
+<P>When <CODE>trial</CODE> invokes <CODE>localmake</CODE>, a local variable named
+<CODE>fred</CODE> is created <EM>inside the invocation of</EM> <CODE>localmake</CODE>!
+That variable is then assigned the value 87.  Then <CODE>localmake</CODE> returns
+to <CODE>trial</CODE>, and <CODE>localmake</CODE>'s local variables disappear.  Back in
+<CODE>trial</CODE>, there is no variable named <CODE>fred</CODE>.
+
+<P>Here's the solution.  If <CODE>localmake</CODE> is an ordinary procedure, there's
+no way it can create a local variable in its caller.  So we have to define
+<CODE>localmake</CODE> as a special kind of procedure:
+
+<P><PRE>.macro localmake :name :value
+output (list &quot;local (word &quot;&quot; :name) &quot;make (word &quot;&quot; :name) :value)
+end
+</PRE>
+
+<P>The command <CODE>.macro</CODE> is like <CODE>to</CODE>, except that the
+procedure it defines is a macro instead of an ordinary procedure.
+(It's a Logo convention that advanced primitives that could be
+confusing to beginners have names beginning with a period.)
+
+<P>It's a little hard to read exactly what this procedure does, so for
+exploratory purposes I'll define an ordinary procedure with the same body:
+
+<P><PRE>to lmake :name :value
+output (list &quot;local (word &quot;&quot; :name) &quot;make (word &quot;&quot; :name) :value)
+end
+
+? <U>show lmake &quot;fred 87</U>
+[local &quot;fred make &quot;fred 87]
+</PRE>
+
+<P>As you see from the example, <CODE>lmake</CODE> outputs a list
+containing the instructions that we would like its caller to carry out.
+
+<P>The macro <CODE>localmake</CODE> outputs the same list of instructions.  But,
+because <CODE>localmake</CODE> is a macro, that output is then <EM>evaluated</EM>
+by the procedure that called <CODE>localmake</CODE>.  If <CODE>trial</CODE> is run
+using the macro version of <CODE>localmake</CODE> instead of the ordinary procedure
+version that didn't work, the effect is as if <CODE>trial</CODE> contained a <CODE>
+local</CODE> instruction and a <CODE>make</CODE> instruction in place of the one
+<CODE>localmake</CODE> invocation.  (If you defined the incorrect version of
+<CODE>localmake</CODE>, you can say
+
+<P><PRE>erase &quot;localmake
+</PRE>
+
+<P>and then the official version will be reloaded from the library
+the next time you use it.)
+
+<P>You may find the expression <CODE>(word &quot;&quot; :name)</CODE> that appears twice
+in the definition of <CODE>localmake</CODE> confusing.  At first glance, it
+seems that there is already a quotation mark in the first input to
+<CODE>localmake</CODE>, namely, <CODE>&quot;fred</CODE>.  But don't forget that that quotation
+mark is not part of the word!  For example, when you say
+
+<P><PRE>print &quot;fred
+</PRE>
+
+<P>Logo doesn't print a quotation mark.  What the quotation mark
+means to Logo is &quot;use the word that follows as the value for this input,
+rather than taking that word as the name of a procedure and invoking that
+procedure to find the input value.&quot;  In this example, the first input
+to <CODE>localmake</CODE> is the word <CODE>fred</CODE> itself, rather than the result
+of invoking a procedure named <CODE>fred</CODE>.  If we want to construct an
+instruction such as
+
+<P><PRE>local &quot;fred
+</PRE>
+
+<P>based on this input, we must put a quotation mark in front of
+the word explicitly.
+
+<P>In fact, so far I've neglected to deal with the fact that a similar
+issue about quotation may arise for the value being assigned to the
+variable.  In the <CODE>trial</CODE> example I used the value 87, a number,
+which is <EM>self-evaluating;</EM> when a number is typed into Logo as
+an expression, the number itself is the value of the expression.
+But if the value is a non-numeric word, then a quotation mark must be
+used for it, too.  The version of <CODE>localmake</CODE> shown so far would
+fail in a case like
+
+<P><PRE>localmake &quot;greeting &quot;hello
+</PRE>
+
+<P>because the macro would return the list
+
+<P><PRE>[local &quot;greeting make &quot;greeting hello]
+</PRE>
+
+<P>which, when evaluated, would try to invoke a procedure named
+<CODE>hello</CODE> instead of using the word itself as the desired value.
+
+<P>The most straightforward solution is to write a procedure that will
+include a quotation mark only when it's needed:
+
+<P><PRE>.macro localmake :name :value
+output (list &quot;local (quoted :name) &quot;make (quoted :name) (quoted :value))
+end
+
+to quoted :thing
+if numberp :thing [output :thing]
+if listp :thing [output :thing]
+output word &quot;&quot; :thing
+end
+</PRE>
+
+<P>A somewhat less obvious solution, but one I find more appealing, is to
+avoid the entire issue of quotation by putting the inputs to <CODE>make</CODE>
+in a list, which we can do by using <CODE>apply</CODE>:
+
+<P><PRE>.macro localmake :name :value
+output (list &quot;local (word &quot;&quot; :name) &quot;apply &quot;&quot;make (list :name :value))
+end
+</PRE>
+
+<P>On the other hand, it may take some thinking to convince
+yourself that the <CODE>&quot;&quot;make</CODE> in that version is correct!
+
+<P>
+
+<P><H2>Backquote</H2>
+
+<P>Even a simple macro like <CODE>localmake</CODE> is very hard to read, and hard
+to write correctly, because of all these invocations of <CODE>list</CODE> and <CODE>
+word</CODE> to build up a structure that's partly constant and partly variable.
+It would be nice if we could use a notation like
+
+<P><PRE>[local &quot;NAME apply &quot;make [NAME VALUE]]
+</PRE>
+
+<P>for an &quot;almost constant&quot; list in which only the words in
+capital letters would be replaced by values of variables.
+
+<P>
+
+
+<P>That particular notation can't work, because in Logo the case of letters
+doesn't matter when a word is used as the name of something.  But we do
+have something almost as good.  We can say
+
+<P><PRE>`[local ,[word &quot;&quot; :name] apply &quot;make [,[:name] ,[:value]]]
+</PRE>
+
+<P>The first character in that line, before the opening bracket,
+is a <EM>backquote,</EM> which is probably near the top left corner
+of your keyboard.  To Logo, it's just an ordinary character, and happens
+to be the name of a procedure in the Berkeley Logo library.  The list
+that follows the backquote above is the input to the procedure.
+
+<P>What the <CODE>`</CODE> procedure does with its input list is to make a copy,
+but wherever a word containing only a comma (<CODE>,</CODE>) appears, what
+comes next must be a list, which is <CODE>run</CODE> to provide the value
+for that position in the copy.  I've put the commas right next to the
+lists that follow them, but this doesn't matter; whenever Logo sees
+a bracket, it delimits the words on both sides of the bracket, just as
+if there were spaces around the bracket.
+
+<P>So if <CODE>:name</CODE> has the value <CODE>fred</CODE> and <CODE>:value</CODE> has the value 87,
+then this sample invocation of <CODE>`</CODE> has the value
+
+<P><PRE>[local &quot;fred apply &quot;make [fred 87]]
+</PRE>
+
+<P>Like macros, backquote is a feature that Berkeley Logo borrows from Lisp.
+It's not hard to implement:
+
+<P><PRE>to ` :backq.list
+if emptyp :backq.list [output []]
+if equalp first :backq.list &quot;, ~
+   [output fput run first butfirst :backq.list
+                ` butfirst butfirst :backq.list]
+if equalp first :backq.list &quot;,@ ~
+   [output sentence run first butfirst :backq.list
+                    ` butfirst butfirst :backq.list]
+if wordp first :backq.list ~
+   [output fput first :backq.list ` butfirst :backq.list]
+output fput ` first :backq.list ` butfirst :backq.list
+end
+</PRE>
+
+<P>This procedure implements one feature I haven't yet described.  If the
+input to <CODE>`</CODE> contains the word <CODE>,@</CODE> (comma atsign), then the
+next member of the list must be a list, which is <CODE>run</CODE> as for comma,
+but the <EM>members</EM> of the result are inserted in the output, instead
+of the result as a whole.  Here's an example:
+
+<P><PRE>? <U>show `[start ,[list &quot;a &quot;b] middle ,@[list &quot;a &quot;b] end]</U>
+[start [a b] middle a b end]
+</PRE>
+
+<P>
+Using backquote, we could rewrite <CODE>localmake</CODE> a little more readably:
+
+<P><PRE>.macro localmake :name :value
+output `[local ,[word &quot;&quot; :name] apply &quot;make [,[:name] ,[:value]]]
+end
+</PRE>
+
+<P>In practice, though, I have to admit that the Berkeley Logo
+library doesn't use backquote in its macro definitions because it's
+noticeably slower than constructing the macro with explicit calls to <CODE>
+list</CODE> and <CODE>word</CODE>.
+
+<P>By the way, this implementation of backquote isn't as complex as some
+Lisp versions.  Most importantly, there is no provision for <EM>nested</EM>
+backquotes, that is, for an invocation of backquote within the input
+to backquote.  (Why would you want to do that?  Think about a macro whose
+job is to generate a definition for another macro.)
+
+<P><H2>Implementing Iterative Commands</H2>
+
+<P>It's time to see how macros can be used to implement iterative control
+structures like <CODE>for</CODE> and <CODE>foreach</CODE> correctly.  I'll concentrate
+on <CODE>foreach</CODE> because it's simpler to implement, but the same ideas
+apply equally well to <CODE>for</CODE>.
+
+<P>Perhaps the most obvious approach is to have the <CODE>foreach</CODE> macro
+output a long instruction list in which the template is applied to each
+member of the list.  That is, if we say
+
+<P><PRE>foreach [a b c] [print ?]
+</PRE>
+
+<P>then the <CODE>foreach</CODE> macro should output the list
+
+<P><PRE>[print &quot;a print &quot;b print &quot;c]
+</PRE>
+
+<P>To achieve precisely this result we'd have to look through
+the template for question marks, replacing each one with a possibly
+quoted datum.  Instead it'll be easier to generate the uglier but
+equivalent instruction list
+
+<P><PRE>[apply [print ?] [a] apply [print ?] [b] apply [print ?] [c]]
+</PRE>
+
+<P>this way:
+
+<P><PRE>.macro foreach :data :template
+output map.se [list &quot;apply :template (list ?)] :data
+end
+</PRE>
+
+<P>(To simplify the discussion, I'm writing a version of <CODE>foreach</CODE>
+that only takes two inputs.  You'll see in a moment that the implementation
+will be complicated by other considerations, so I want to avoid unnecessary
+complexity now.  At the end I'll show you the official, complete
+implementation.)
+
+<P>This version works correctly, and it's elegantly written.  We could stop
+here.  Unfortunately, this version is inefficient, for two reasons.  First,
+it uses another higher order procedure, <CODE>map.se</CODE>, to construct the list of
+instructions to evaluate.  Second, for a large data input, we construct
+a very large instruction list, using lots of computer memory, just so that
+we can evaluate the instructions once and throw the list away.
+
+<P>Another approach is to let the <CODE>foreach</CODE> macro invoke itself recursively.
+This is a little tricky; you'll see that <CODE>foreach</CODE> does not actually
+invoke itself within itself.  Instead, it constructs an instruction list
+that contains another use of <CODE>foreach</CODE>.  For example, the instruction
+
+<P><PRE>foreach [a b c] [print ?]
+</PRE>
+
+<P>will generate the instruction list
+
+<P><PRE>[apply [print ?] [a] foreach [b c] [print ?]]
+</PRE>
+
+<P>Here's how to write that:
+
+<P><PRE>.macro foreach :data :template
+output `[apply ,[:template] [,[first :data]]
+         foreach ,[butfirst :data] ,[:template]]
+end
+</PRE>
+
+<P>In this case the desired instruction list is long enough
+so that I've found it convenient to use the backquote notation to
+express my intentions.  If you prefer, you could say
+
+<P><PRE>.macro foreach :data :template
+output (list &quot;apply :template (list (first :data))
+             &quot;foreach (butfirst :data) :template)
+end
+</PRE>
+
+<P>This implementation (in either the backquote version or
+the explicit list constructor version) avoids the possibility of
+constructing huge instruction lists; the constructed list has only
+the computation for the first datum and a recursive <CODE>foreach</CODE> that
+handles the entire rest of the problem.
+
+<P>But this version is still slower than the non-macro implementation
+of <CODE>foreach</CODE> given in Chapter 10.  Constructing an instruction
+list and then evaluating it is just a slower process than simply doing
+the necessary computation within <CODE>foreach</CODE> itself.  And that
+earlier approach works fine unless the template involves <CODE>stop</CODE>,
+<CODE>output</CODE>, or <CODE>local</CODE>.  We could have our cake and eat it too if
+we could find a way to use the non-macro approach, but notice when
+the template tries to stop its computation.  This version is quite a bit
+trickier than the ones we've seen until now:
+
+<P><PRE>.macro foreach :data :template
+catch &quot;foreach.catchtag ~
+      [output foreach.done runresult [foreach1 :data :template]]
+output []
+end
+
+to foreach1 :data :template
+if emptyp :data [throw &quot;foreach.catchtag]
+apply :template (list first :data)
+.maybeoutput foreach1 butfirst :data :template
+end
+
+to foreach.done :foreach.result
+if emptyp :foreach.result [output [stop]]
+output list &quot;output quoted first :foreach.result
+end
+</PRE>
+
+<P>To help you understand how this works, let's first consider what happens
+if the template does not include <CODE>stop</CODE> or <CODE>output</CODE>.  In that
+case, the program structure is essentially this:
+
+<P><PRE>.macro simpler.foreach :data :template
+catch &quot;foreach.catchtag ~
+      [this.stuff.never.invoked run [simpler.foreach1 :data :template]]
+output []
+end
+
+to simpler.foreach1 :data :template
+if emptyp :data [throw &quot;foreach.catchtag]
+apply :template (list first :data)
+simpler.foreach1 butfirst :data :template
+end
+</PRE>
+
+<P>The instruction list that's evaluated by the <CODE>catch</CODE> runs
+a smaller instruction list that invokes <CODE>simpler.foreach1</CODE>.  That
+procedure is expected to output a value, which is then used as the input
+to some other computation (namely, <CODE>foreach.done</CODE> in the actual version).
+But when <CODE>simpler.foreach1</CODE> reaches its base case, it doesn't output
+anything; it <CODE>throw</CODE>s back to the instruction after the <CODE>catch</CODE>,
+which outputs an empty list.  So all of the work of <CODE>foreach</CODE> is done
+within these procedures; the macro outputs an empty instruction list, which
+is evaluated by the caller of <CODE>foreach</CODE>, but that evaluation has no
+effect.
+
+<P>Now forget about the <CODE>simpler</CODE> version and return to the actual
+<CODE>foreach</CODE>.  What if the template carries out a <CODE>stop</CODE> or <CODE>
+output</CODE>?  If that happens, <CODE>foreach1</CODE> will never reach its base
+case, and will therefore not <CODE>throw</CODE>.  It will either stop or
+output a value.  The use of <CODE>.maybeoutput</CODE> in <CODE>foreach1</CODE> is
+what makes it possible for <CODE>foreach1</CODE> to function either as a command
+(if it stops) or as an operation (if it outputs) without causing an error
+when it invokes itself recursively.  If the recursive invocation stops,
+so does the outer invocation.  If the recursive invocation outputs a value,
+the outer invocation outputs that value.
+
+<P><CODE>Foreach</CODE> invoked <CODE>foreach1</CODE> using Berkeley Logo's <CODE>runresult</CODE> primitive
+operation.  <CODE>Runresult</CODE> is just like <CODE>run</CODE>, except that it always
+outputs a value, whether or not the computation that it runs produces
+a value.  If so, then <CODE>runresult</CODE> outputs a one-member list containing
+the value.  If not, then <CODE>runresult</CODE> outputs an empty list.
+
+<P>The output from <CODE>runresult</CODE> is used as input to <CODE>foreach.done</CODE>,
+whose job is to construct an instruction list as the overall output from
+the <CODE>foreach</CODE> macro.  If the input to <CODE>foreach.done</CODE> is empty,
+that means that the template included a <CODE>stop</CODE>, and so <CODE>foreach</CODE>
+should generate a <CODE>stop</CODE> instruction to be evaluated by its caller.
+If the input isn't empty, then the template included an <CODE>output</CODE>
+instruction, and <CODE>foreach</CODE> should generate an <CODE>output</CODE> instruction
+as its return value.
+
+<P>This version is quite fast, and handles <CODE>stop</CODE> and <CODE>output</CODE>
+correctly.  It does not, however, handle <CODE>local</CODE> correctly; the
+variable will be local to <CODE>foreach1</CODE>, not to the caller.  It was
+hard to decide which version to use in the Berkeley Logo library, but
+slowing down every use of <CODE>foreach</CODE> seemed too high a price to pay
+for <CODE>local</CODE>.  That's why, for example, procedure <CODE>onegame</CODE> in
+the solitaire program of Chapter 4 includes the instructions
+
+<P><PRE>local map [word &quot;num ?] :numranks
+foreach :numranks [make word &quot;num ? 4]
+</PRE>
+
+<P>instead of the more natural
+
+<P><PRE>foreach :numranks [localmake word &quot;num ? 4]
+</PRE>
+
+<P>That single instruction would work with the first implementation
+of <CODE>foreach</CODE> in this chapter, but doesn't work with the actual
+Berkeley Logo implementation!
+
+<P><H2>Debugging Macros</H2>
+
+<P>It's easy to make mistakes when writing a macro, because it's hard to keep
+straight what has to be quoted and what doesn't, for example.  And it's
+hard to debug a macro, because you can't easily see the instruction list
+that it outputs.  You can't say
+
+<P><PRE>show foreach ...
+</PRE>
+
+<P>because the output from <CODE>foreach</CODE> is <EM>evaluated,</EM> not
+passed on to <CODE>show</CODE>.
+
+<P>One solution is to trace the macro.
+
+<P><PRE>? <U>trace &quot;foreach</U>
+? <U>foreach [a b c] [print ?]</U>
+( foreach [a b c] [print ?] )
+a
+b
+c
+foreach outputs []
+? <U>foreach [a b 7 c] [if numberp ? [stop] print ?]</U>
+( foreach [a b 7 c] [if numberp ? [stop] print ?] )
+a
+b
+foreach outputs [stop]
+Can only use stop inside a procedure
+</PRE>
+
+<P>In this case, I got an error message because, just as the
+message says, it doesn't make sense to use <CODE>stop</CODE> in a template
+unless this invocation of <CODE>foreach</CODE> is an instruction inside
+a procedure definition.  Here I invoked <CODE>foreach</CODE> directly at
+the Logo prompt.
+
+<P>The Berkeley Logo library provides another solution, a
+<CODE>macroexpand</CODE> operation that takes as its input a Logo expression beginning
+with the name of a macro.  It outputs the expression that the macro would
+output, without causing that expression to be evaluated:
+
+<P><PRE>? <U>show macroexpand [foreach [a b 7 c] [if numberp ? [stop] print ?]]</U>
+a
+b
+[stop]
+</PRE>
+
+<P>This time I didn't get an error message, because the instruction
+list that <CODE>foreach</CODE> outputs wasn't actually evaluated; it became the
+input to <CODE>show</CODE>, which is why it appears at the end of the example.
+
+<P><CODE>Macroexpand</CODE> works by using <CODE>define</CODE> and <CODE>text</CODE> to define,
+temporarily, a new procedure that's just like the macro it wants to expand,
+but an ordinary procedure instead of a macro:
+
+<P><PRE>to macroexpand :expression
+define &quot;temporary.macroexpand.procedure text first :expression
+...
+end
+</PRE>
+
+<P>You might enjoy filling in the rest of this procedure, as an
+exercise in advanced Logo programming, before you read the version
+in the library.
+
+<P>(What if you want to do the opposite, defining a macro with the same text
+as an ordinary procedure?  Berkeley Logo includes a <CODE>.defmacro</CODE> command,
+which is just like <CODE>define</CODE> except that the resulting procedure is a
+macro.  We don't need two versions of <CODE>text</CODE>, because the text of a
+macro looks just like the text of an ordinary procedure.  To tell the
+difference, there is a primitive predicate <CODE>macrop</CODE> that takes a word
+as input, and outputs <CODE>true</CODE> if that word is the name of a macro.)
+
+<P><H2>The Real Thing</H2>
+
+<P>Here is the complete version of <CODE>foreach</CODE>, combining the macro
+structure developed in this chapter with the full template flexibility
+from Chapter 10.
+
+<P><PRE>.macro foreach [:foreach.inputs] 2
+catch &quot;foreach.catchtag ~
+      [output foreach.done runresult [foreach1 butlast :foreach.inputs
+                                               last :foreach.inputs 1]]
+output []
+end
+
+to foreach1 :template.lists :foreach.template :template.number
+if emptyp first :template.lists [throw &quot;foreach.catchtag]
+apply :foreach.template firsts :template.lists
+.maybeoutput foreach1 butfirsts :template.lists ~
+                      :foreach.template :template.number+1
+end
+
+to foreach.done :foreach.result
+if emptyp :foreach.result [output [stop]]
+output list &quot;output quoted first :foreach.result
+end
+</PRE>
+
+<P>And here, without any discussion, is the actual library version of
+<CODE>for</CODE>.  This, too, combines the ideas of this chapter with
+those of Chapter 10.
+
+<P><PRE>.macro for :for.values :for.instr
+localmake &quot;for.var first :for.values
+localmake &quot;for.initial run first butfirst :for.values
+localmake &quot;for.final run item 3 :for.values
+localmake &quot;for.step forstep
+localmake &quot;for.tester (ifelse :for.step &lt; 0
+                              [[(thing :for.var) &lt; :for.final]]
+                              [[(thing :for.var) &gt; :for.final]])
+local :for.var
+catch &quot;for.catchtag [output for.done runresult [forloop :for.initial]]
+output []
+end
+
+to forloop :for.initial
+make :for.var :for.initial
+if run :for.tester [throw &quot;for.catchtag]
+run :for.instr
+.maybeoutput forloop ((thing :for.var) + :for.step)
+end
+
+to for.done :for.result
+if emptyp :for.result [output [stop]]
+output list &quot;output quoted first :for.result
+end
+
+to forstep
+if equalp count :for.values 4 [output run last :for.values]
+output ifelse :for.initial &gt; :for.final [-1] [1]
+end
+</PRE>
+
+
+
+<P><A HREF="../v2-toc2.html">(back to Table of Contents)</A>
+<P><A HREF="../v2ch11/v2ch11.html"><STRONG>BACK</STRONG></A>
+chapter thread <A HREF="../v2ch13/v2ch13.html"><STRONG>NEXT</STRONG></A>
+
+<P>
+<ADDRESS>
+<A HREF="../index.html">Brian Harvey</A>, 
+<CODE>bh@cs.berkeley.edu</CODE>
+</ADDRESS>
+</BODY>
+</HTML>