commit 8a59d450989ec4a57dc4c2c20286a11a7775de47
Author: Greg Hendershott <greghendershott@gmail.com>
Date: Wed, 24 Oct 2012 15:11:13 -0400
Initial commit.
Diffstat:
| A | main.html | | | 211 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | main.rkt | | | 818 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | racket.css | | | 233 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | scribble-common.js | | | 153 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | scribble-style.css | | | 0 | |
| A | scribble.css | | | 471 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
6 files changed, 1886 insertions(+), 0 deletions(-)
diff --git a/main.html b/main.html
@@ -0,0 +1,210 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html><head><meta http-equiv="content-type" content="text-html; charset=utf-8" /><title>Fear of Macros</title><link rel="stylesheet" type="text/css" href="scribble.css" title="default" /><link rel="stylesheet" type="text/css" href="racket.css" title="default" /><link rel="stylesheet" type="text/css" href="scribble-style.css" title="default" /><script type="text/javascript" src="scribble-common.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="scribble-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">►</a></td><td></td><td><a href="" class="tocviewselflink" pltdoc="x">Fear of Macros</a></td></tr></table></div><div class="tocviewsublistonly" style="display: none;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="#(part._.Introduction)" class="tocviewlink" pltdoc="x">Introduction</a></td></tr><tr><td align="right">2 </td><td><a href="#(part._.The_plan_of_attack)" class="tocviewlink" pltdoc="x">The plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="#(part._.Transformers)" class="tocviewlink" pltdoc="x">Transformers</a></td></tr><tr><td align="right">4 </td><td><a href="#(part._.Pattern_matching__syntax-case_and_syntax-rules)" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="#(part._.Syntax_parameters)" class="tocviewlink" pltdoc="x">Syntax parameters</a></td></tr><tr><td align="right">6 </td><td><a href="#(part._.Robust_macros__syntax-parse)" class="tocviewlink" pltdoc="x">Robust macros:<span class="mywbr"> </span> syntax-<wbr></wbr>parse</a></td></tr><tr><td align="right">7 </td><td><a href="#(part._.Other_questions)" class="tocviewlink" pltdoc="x">Other questions</a></td></tr><tr><td align="right">8 </td><td><a href="#(part._.References_.Acknowledgements)" class="tocviewlink" pltdoc="x">References/<span class="mywbr"> </span>Acknowledgements</a></td></tr><tr><td align="right">9 </td><td><a href="#(part._.Epilog)" class="tocviewlink" pltdoc="x">Epilog</a></td></tr></table></div></div></div><div class="tocsub"><table class="tocsublist" cellspacing="0"><tr><td><span class="tocsublinknumber">1<tt> </tt></span><a href="#(part._.Introduction)" class="tocsubseclink" pltdoc="x">Introduction</a></td></tr><tr><td><span class="tocsublinknumber">2<tt> </tt></span><a href="#(part._.The_plan_of_attack)" class="tocsubseclink" pltdoc="x">The plan of attack</a></td></tr><tr><td><span class="tocsublinknumber">3<tt> </tt></span><a href="#(part._.Transformers)" class="tocsubseclink" pltdoc="x">Transformers</a></td></tr><tr><td><span class="tocsublinknumber">3.1<tt> </tt></span><a href="#(part._.What_is_a_syntax_transformer_)" class="tocsubseclink" pltdoc="x">What is a syntax transformer?</a></td></tr><tr><td><span class="tocsublinknumber">3.2<tt> </tt></span><a href="#(part._.What_is_the_input_)" class="tocsubseclink" pltdoc="x">What is the input?</a></td></tr><tr><td><span class="tocsublinknumber">3.3<tt> </tt></span><a href="#(part._.Actually_transforming_the_input)" class="tocsubseclink" pltdoc="x">Actually transforming the input</a></td></tr><tr><td><span class="tocsublinknumber">3.4<tt> </tt></span><a href="#(part._.Compile_time_vs__run_time)" class="tocsubseclink" pltdoc="x">Compile time vs. run time</a></td></tr><tr><td><span class="tocsublinknumber">4<tt> </tt></span><a href="#(part._.Pattern_matching__syntax-case_and_syntax-rules)" class="tocsubseclink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td><span class="tocsublinknumber">4.1<tt> </tt></span><a href="#(part._.Patterns_and_templates)" class="tocsubseclink" pltdoc="x">Patterns and templates</a></td></tr><tr><td><span class="tocsublinknumber">4.1.1<tt> </tt></span><a href="#(part.__.A_pattern_variable_can_t_be_used_outside_of_a_template_)" class="tocsubseclink" pltdoc="x">"A pattern variable can’t be used outside of a template"</a></td></tr><tr><td><span class="tocsublinknumber">5<tt> </tt></span><a href="#(part._.Syntax_parameters)" class="tocsubseclink" pltdoc="x">Syntax parameters</a></td></tr><tr><td><span class="tocsublinknumber">6<tt> </tt></span><a href="#(part._.Robust_macros__syntax-parse)" class="tocsubseclink" pltdoc="x">Robust macros:<span class="mywbr"> </span> syntax-<wbr></wbr>parse</a></td></tr><tr><td><span class="tocsublinknumber">7<tt> </tt></span><a href="#(part._.Other_questions)" class="tocsubseclink" pltdoc="x">Other questions</a></td></tr><tr><td><span class="tocsublinknumber">7.1<tt> </tt></span><a href="#(part._.What_s_the_point_of_with-syntax_)" class="tocsubseclink" pltdoc="x">What’s the point of <span class="RktSym">with-<wbr></wbr>syntax</span>?</a></td></tr><tr><td><span class="tocsublinknumber">7.2<tt> </tt></span><a href="#(part._.What_s_the_point_of_begin-for-syntax_)" class="tocsubseclink" pltdoc="x">What’s the point of <span class="RktSym">begin-<wbr></wbr>for-<wbr></wbr>syntax</span>?</a></td></tr><tr><td><span class="tocsublinknumber">7.3<tt> </tt></span><a href="#(part._.What_s_the_point_of_racket_splicing_)" class="tocsubseclink" pltdoc="x">What’s the point of <span class="RktSym">racket/<span class="mywbr"> </span>splicing</span>?</a></td></tr><tr><td><span class="tocsublinknumber">8<tt> </tt></span><a href="#(part._.References_.Acknowledgements)" class="tocsubseclink" pltdoc="x">References/<span class="mywbr"> </span>Acknowledgements</a></td></tr><tr><td><span class="tocsublinknumber">9<tt> </tt></span><a href="#(part._.Epilog)" class="tocsubseclink" pltdoc="x">Epilog</a></td></tr></table></div></div><div class="maincolumn"><div class="main"><div class="versionbox"><span class="versionNoNav">Version: 5.3</span></div><h2><a name="(part._.Fear_of_.Macros)"></a>Fear of Macros</h2><p><span class="Smaller">Copyright (c) 2012 by Greg Hendershott. All rights reserved.</span></p><table cellspacing="0"><tr><td><p><span class="hspace"> </span><a href="#(part._.Introduction)" class="toptoclink" pltdoc="x">1<span class="hspace"> </span>Introduction</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.The_plan_of_attack)" class="toptoclink" pltdoc="x">2<span class="hspace"> </span>The plan of attack</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.Transformers)" class="toptoclink" pltdoc="x">3<span class="hspace"> </span>Transformers</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.What_is_a_syntax_transformer_)" class="toclink" pltdoc="x">3.1<span class="hspace"> </span>What is a syntax transformer?</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.What_is_the_input_)" class="toclink" pltdoc="x">3.2<span class="hspace"> </span>What is the input?</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.Actually_transforming_the_input)" class="toclink" pltdoc="x">3.3<span class="hspace"> </span>Actually transforming the input</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.Compile_time_vs__run_time)" class="toclink" pltdoc="x">3.4<span class="hspace"> </span>Compile time vs. run time</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.Pattern_matching__syntax-case_and_syntax-rules)" class="toptoclink" pltdoc="x">4<span class="hspace"> </span>Pattern matching: syntax-case and syntax-rules</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.Patterns_and_templates)" class="toclink" pltdoc="x">4.1<span class="hspace"> </span>Patterns and templates</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part.__.A_pattern_variable_can_t_be_used_outside_of_a_template_)" class="toclink" pltdoc="x">4.1.1<span class="hspace"> </span>"A pattern variable can’t be used outside of a template"</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.Syntax_parameters)" class="toptoclink" pltdoc="x">5<span class="hspace"> </span>Syntax parameters</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.Robust_macros__syntax-parse)" class="toptoclink" pltdoc="x">6<span class="hspace"> </span>Robust macros: syntax-parse</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.Other_questions)" class="toptoclink" pltdoc="x">7<span class="hspace"> </span>Other questions</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.What_s_the_point_of_with-syntax_)" class="toclink" pltdoc="x">7.1<span class="hspace"> </span>What’s the point of <span class="RktSym">with-syntax</span>?</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.What_s_the_point_of_begin-for-syntax_)" class="toclink" pltdoc="x">7.2<span class="hspace"> </span>What’s the point of <span class="RktSym">begin-for-syntax</span>?</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.What_s_the_point_of_racket_splicing_)" class="toclink" pltdoc="x">7.3<span class="hspace"> </span>What’s the point of <span class="RktSym">racket/splicing</span>?</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.References_.Acknowledgements)" class="toptoclink" pltdoc="x">8<span class="hspace"> </span>References/Acknowledgements</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="#(part._.Epilog)" class="toptoclink" pltdoc="x">9<span class="hspace"> </span>Epilog</a></p></td></tr></table><h3>1<tt> </tt><a name="(part._.Introduction)"></a>Introduction</h3><p>I learned Racket after 25 years of doing C/C++ imperative programming.</p><p>Some psychic whiplash resulted.</p><p>"All the parentheses" was actually not a big deal. Instead, the first
+mind warp was functional programming. Before long I wrapped my brain
+around it, and went on to become comfortable and effective with many
+other aspects and features of Racket.</p><p>But two final frontiers remained: Macros and continuations.</p><p>I found that simple macros were easy and understandable, plus there
+were many good tutorials available. But the moment I stepped past
+routine pattern-matching, I kind of fell off a cliff into a
+terminology soup. I marinaded myself in material, hoping it would
+eventually sink in after enough re-readings. I even found myself using
+trial and error, rather than having a clear mental model what was
+going on. Gah.</p><p>I’m starting to write this at the point where the shapes are slowly
+emerging from the fog.</p><p>My primary motive is selfish. Explaining something forces me to learn
+it more thorougly. Plus I expect that if I write something with
+mistakes, other people will be eager to point them out and correct
+me. Is that a social-engineering variation of meta-programming? Next
+question, please. :)</p><p>Finally I do hope it may help other people who have a similar
+background and/or learning style as me.</p><p>I want to show how Racket macro features have evolved as solutions to
+problems or annoyances. I learn more quickly and deeply when I
+discover the answer to a question I already have, or find the solution
+to a problem whose pain I already feel. Therefore I’ll give you the
+questions and problems first, so that you can better appreciate and
+understand the answers and solutions.</p><h3>2<tt> </tt><a name="(part._.The_plan_of_attack)"></a>The plan of attack</h3><p>The macro system you will mostly want to use for production-quality
+macros is called <span class="RktSym">syntax-parse</span>. And don’t worry, we’ll get to
+that soon.</p><p>But if we start there, you’re likely to feel overwhelmed by concepts
+and terminology, and get very confused. I did.</p><p>1. Instead let’s start with the basics: A syntax object and a function
+to change it (a "transformer"). We’ll work at that level for awhile to
+get comfortable and to de-mythologize this whole macro business.</p><p>2. Next, we’ll realize that some pattern-matching would make life
+easier. We’ll learn about <span class="RktSym">syntax-case</span>, and its shorthand
+cousin, <span class="RktSym">define-syntax-rule</span>. We’ll discover we can get
+confused if we want to munge pattern variables before sticking them
+back in the template, and learn how to do that.</p><p>3. At this point we’ll be able to write many useful macros. But, what
+if we want to write the ever-popular anaphoric if, with a "magic
+variable"? It turns out we’ve been protected from making certain kind
+of mistakes. When we want to do this kind of thing on purpose, we use
+a <span class="RktSym">syntax</span><span class="stt"> </span><span class="RktSym">parameter</span>. [There are other, older ways to do
+this. We won’t look at them. We also won’t spend a lot of time talking
+about "hygiene".]</p><p>4. Finally, we’ll realize that our macros could be smarter when
+they’re used in error. Normal Racket functions can optionally have
+contracts and types. These can catch mistakes and provide clear,
+useful error messages. It would be great if there were somthing
+similar for macros, and there is. One of the more-recent Racket macro
+enhancements is <span class="RktSym">syntax-parse</span>.</p><h3>3<tt> </tt><a name="(part._.Transformers)"></a>Transformers</h3><p><table cellspacing="0"><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">YOU ARE INSIDE A ROOM.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">THERE ARE KEYS ON THE GROUND.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">THERE IS A SHINY BRASS LAMP NEARBY.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt"></span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">IF YOU GO THE WRONG WAY, YOU WILL BECOME</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">HOPELESSLY LOST AND CONFUSED.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt"></span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">> pick up the keys</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt"></span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">YOU HAVE A SYNTAX TRANSFORMER</span></span></p></td></tr></table></p><h4>3.1<tt> </tt><a name="(part._.What_is_a_syntax_transformer_)"></a>What is a syntax transformer?</h4><p>A syntax transformer is not one of the トランスフォーマ
+<a href="http://en.wikipedia.org/wiki/Transformers">transformers</a>.</p><p>Instead, it is quite simple. It is a function. The function takes
+syntax and returns syntax. It transforms syntax.</p><p>Here’s a transformer function that ignores its input syntax, and
+always outputs syntax for a string literal:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktSym">foo</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktVal">"I am foo"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"I am foo"</span></p></td></tr></table></blockquote><p>When we use <span class="RktSym">define-syntax</span>, we’re making a transformer
+<span style="font-style: italic">binding</span>. This tells the Racket compiler, "Whenever you
+encounter a chunk of syntax starting with <span class="RktSym">foo</span>, please give it
+to my transformer function, and replace it with the syntax I give back
+to you." So Racket will give anything that looks like <span class="RktPn">(</span><span class="RktSym">foo</span><span class="stt"> </span><span class="RktSym">...</span><span class="RktPn">)</span> to our function, and we can change it. Much like a
+search-and-replace.</p><p>Maybe you know that the usual way to define a function in Racket:</p><p><span class="RktPn">(</span><span class="RktSym">define</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">f</span><span class="stt"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktSym">...</span><span class="RktPn">)</span></p><p>is shorthand for:</p><p><span class="RktPn">(</span><span class="RktSym">define</span><span class="stt"> </span><span class="RktSym">f</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">x</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="RktPn">)</span></p><p>That shorthand lets you avoid typing <span class="RktSym">lambda</span> and some parentheses.</p><p>Well there is a similar shorthand for <span class="RktSym">define-syntax</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">also-foo</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktVal">"I am also foo"</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">also-foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"I am also foo"</span></p></td></tr></table></blockquote><p>What we want to remember is that this is simply shorthand. We are
+still defining a transformer function, which takes syntax and returns
+syntax. Everything we do with macros, will be built on top of this
+basic idea. It’s not magic.</p><p>Speaking of shorthand, there is also a shorthand for <span class="RktSym">syntax</span>,
+which is <span class="stt">#</span><span class="stt">’</span><span class="stt"></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">quoted-foo</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktVal">"I am also foo, using #' instead of syntax"</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">quoted-foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"I am also foo, using #' instead of syntax"</span></p></td></tr></table></blockquote><p>Of course, we can emit syntax that is more interesting than a
+string literal. How about returning <span class="RktPn">(</span><span class="RktSym">displayln</span><span class="stt"> </span><span class="RktVal">"hi"</span><span class="RktPn">)</span>?</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">say-hi</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace"> </span><span class="RktVal">"hi"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">say-hi</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">hi</span></p></td></tr></table></blockquote><p>When Racket expands our program, it sees the occurrence of
+<span class="RktPn">(</span><span class="RktSym">say-hi</span><span class="RktPn">)</span>, and sees it has a transformer function for that. It
+calls our function with the old syntax, and we return the new syntax,
+which is used to evaluate and run our program.</p><h4>3.2<tt> </tt><a name="(part._.What_is_the_input_)"></a>What is the input?</h4><p>Our examples so far have been ignoring the input syntax, and
+outputting a fixed syntax. Usually, we want to transform the input to
+something else.</p><p>But let’s start by looking at what the input <span style="font-style: italic">is</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">show-me</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">print</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">void</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">show-me</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">i</span><span class="hspace"> </span><span class="RktVal">am</span><span class="hspace"> </span><span class="RktVal">a</span><span class="hspace"> </span><span class="RktVal">list</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">#<syntax:10:0 (show-me (quote (i am a list)))></span></p></td></tr></table></blockquote><p>The <span class="RktPn">(</span><span class="RktSym">print</span><span class="stt"> </span><span class="RktSym">stx</span><span class="RktPn">)</span> shows what our transformer is given: a syntax
+object.</p><p>A syntax object consists of several things. The first part is the
+s-expression representing the code, such as <span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">i</span><span class="stt"> </span><span class="RktVal">am</span><span class="stt"> </span><span class="RktVal">a</span><span class="stt"> </span><span class="RktVal">list</span><span class="RktVal">)</span>. Racket (and Scheme and Lisp) expressions are s-expressions—<wbr></wbr>
+code and data have the same structure, and this makes it vastly easier
+to rewrite syntax, i.e. write macros.</p><p>Racket syntax is also decorated with some interesting information such
+as the source file, line number, and column. Finally, it has
+information about lexical scoping (which you don’t need to worry about
+now, but will turn out to be important later.)</p><p>There are a variety of functions available to access a syntax object:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">if</span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">list</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#f</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(if<span class="stt"> </span>x<span class="stt"> </span>(list<span class="stt"> </span>"true")<span class="stt"> </span>#f)</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">syntax-e</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(#<syntax:11:0 if><span class="stt"> </span>#<syntax:11:0 x><span class="stt"> </span>#<syntax:11:0 (list "true")><span class="stt"> </span>#<syntax:11:0 #f>)</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">syntax->list</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(#<syntax:11:0 if><span class="stt"> </span>#<syntax:11:0 x><span class="stt"> </span>#<syntax:11:0 (list "true")><span class="stt"> </span>#<syntax:11:0 #f>)</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">syntax-source</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'eval</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">syntax-line</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">11</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">syntax-column</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">0</span></p></td></tr></table></blockquote><p>When we want to transform syntax, we’ll generally take the pieces we
+were given, maybe rearrange their order, perhaps change some of the
+pieces, and often introduce brand-new pieces.</p><h4>3.3<tt> </tt><a name="(part._.Actually_transforming_the_input)"></a>Actually transforming the input</h4><p>Let’s write a transformer function that reverses the syntax it was
+given:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">reverse</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">cdr</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="hspace"> </span><span class="RktVal">"backwards"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="RktSym">values</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"i"</span></p></td></tr><tr><td><p><span class="RktRes">"am"</span></p></td></tr><tr><td><p><span class="RktRes">"backwards"</span></p></td></tr></table></blockquote><p>What’s going on here? First we take the input syntax, and give it to
+<span class="RktSym">syntax->datum</span>. This converts the syntax into a plain old list:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="hspace"> </span><span class="RktVal">"backwards"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="RktSym">values</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(reverse-me<span class="stt"> </span>"backwards"<span class="stt"> </span>"am"<span class="stt"> </span>"i"<span class="stt"> </span>values)</span></p></td></tr></table></blockquote><p>Using <span class="RktSym">cdr</span> slics off the first item of the list,
+<span class="RktSym">reverse-me</span>, leaving the rmainder:
+<span class="RktPn">(</span><span class="RktVal">"backwards"</span><span class="stt"> </span><span class="RktVal">"am"</span><span class="stt"> </span><span class="RktVal">"i"</span><span class="stt"> </span><span class="RktSym">values</span><span class="RktPn">)</span>. Passing that to
+<span class="RktSym">reverse</span> changes it to <span class="RktPn">(</span><span class="RktSym">values</span><span class="stt"> </span><span class="RktVal">"i"</span><span class="stt"> </span><span class="RktVal">"am"</span><span class="stt"> </span><span class="RktVal">"backwards"</span><span class="RktPn">)</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">reverse</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">cdr</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">"backwards"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="RktVal">values</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(values<span class="stt"> </span>"i"<span class="stt"> </span>"am")</span></p></td></tr></table></blockquote><p>Finally we use <span class="RktSym">syntax->datum</span> to convert this back to
+<span class="RktSym">syntax</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktVal">#f</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">values</span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"backwards"</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#<syntax (values "i" "am" "backwards")></span></p></td></tr></table></blockquote><p>That’s what our transformer function gives back to the Racket
+compiler, and <span style="font-style: italic">that</span> syntax is evaluated:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">values</span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"backwards"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"i"</span></p></td></tr><tr><td><p><span class="RktRes">"am"</span></p></td></tr><tr><td><p><span class="RktRes">"backwards"</span></p></td></tr></table></blockquote><h4>3.4<tt> </tt><a name="(part._.Compile_time_vs__run_time)"></a>Compile time vs. run time</h4><p>Normal Racket code runs at ... run time. Duh.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Instead of "compile time vs. run time", you may hear it
+described as "syntax phase vs. runtime phase". Same difference.</p></blockquote></blockquote></blockquote><p>But a syntax transformer is run by the Racket compiler, as part of the
+process of parsing, expanding and understanding your code. In other
+words, your syntax transformer function is evaluated at compile time.</p><p>This aspect of macros lets you do things that simply aren’t possible
+in normal code. One of the classic examples, is something like the
+Racket <span class="RktSym">if</span> form:</p><p><span class="RktPn">(</span><span class="RktSym">if</span><span class="stt"> </span><span class="RktSym"><condition></span><span class="stt"> </span><span class="RktSym"><true-expression></span><span class="stt"> </span><span class="RktSym"><false-expression></span><span class="RktPn">)</span></p><p>If <span class="RktSym">if</span> were implemented as a function, all of the arguments
+would be evaluated before being provided to the function.</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">cond</span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">else</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace"> </span><span class="RktVal">#t</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">"true"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>That seems to work. However, how about this:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace"> </span><span class="RktVal">#t</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0"><tr><td><p><span class="RktOut">true</span></p></td></tr><tr><td><p><span class="RktOut">false</span></p></td></tr></table></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>One answer is that functional programming is good, and
+side-effects are bad. But avoiding side-effects isn’t always
+practical.</p></blockquote></blockquote></blockquote><p>Oops. Because the expressions have a side-effect, it’s obvious that
+they are both evaluated. And that could be a problem—<wbr></wbr>what if the
+side-effect includes deleting a file on disk? You wouldn’t want
+<span class="RktPn">(</span><span class="RktSym">if</span><span class="stt"> </span><span class="RktSym">user-wants-file-deleted?</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">delete-file</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">void</span><span class="RktPn">)</span><span class="RktPn">)</span> to delete
+a file even when <span class="RktSym">user-wants-file-deleted?</span> is <span class="RktVal">#f</span>.</p><p>So this simply can’t work as a plain function. However a syntax
+transformer can rearrange the syntax – rewrite the code – at compile
+time. The pieces of syntax are moved around, but they aren’t actually
+evaluated until run time.</p><p>Here is one way to do this:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->list</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadr</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">caddr</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadddr</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktVal">#t</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktOut">true</span></p></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktVal">#f</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktOut">false</span></p></td></tr><tr><td><p><span class="RktRes">"false"</span></p></td></tr></table></blockquote><p>That gave the right answer. But how? Let’s pull out the transformer
+function itself, and see what it did. We start with an example of some
+input syntax:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">#<syntax:31:0 (our-if-v2 #t "true" "false")></span></p></td></tr></table></blockquote><p>1. We take the original syntax, and use <span class="RktSym">syntax->datum</span> to
+change it into a plain Racket <span class="RktSym">list</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">(our-if-v2 #t true false)</span></p></td></tr></table></blockquote><p>2. To change this into a Racket <span class="RktSym">cond</span> form, we need to take
+the three interesting pieces—<wbr></wbr>the condition, true-expression, and
+false-expression—<wbr></wbr>from the list using <span class="RktSym">cadr</span>, <span class="RktSym">caddr</span>,
+and <span class="RktSym">cadddr</span> and arrange them into a <span class="RktSym">cond</span> form:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktSym">`</span><span class="RktPn">(</span><span class="RktSym">cond</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">[</span><span class="RktSym">,</span><span class="RktPn">(</span><span class="RktSym">cadr</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">,</span><span class="RktPn">(</span><span class="RktSym">caddr</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">[</span><span class="RktSym">else</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">,</span><span class="RktPn">(</span><span class="RktSym">cadddr</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote><p>3. Finally, we change that into <span class="RktSym">syntax</span> using
+<span class="RktSym">datum->syntax</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadr</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">caddr</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadddr</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktRes">#<syntax (cond (#t "true") (else "fals...></span></p></td></tr></table></blockquote><p>So that works, but using <span class="RktSym">cdddr</span> etc. to destructure a list is
+painful and error-prone. Maybe you know Racket’s <span class="RktSym">match</span>?
+Using that would let us do pattern-matching.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Notice that we don’t care about the first item in the
+syntax list. We didn’t take <span class="RktPn">(</span><span class="RktSym">car</span><span class="stt"> </span><span class="RktSym">xs</span><span class="RktPn">)</span> in our-if-v2, and we
+didn’t use <span class="RktSym">name</span> when we used pattern-matching. In general, a
+syntax transformer won’t care about that, because it is the name of
+the transformer binding. In other words, a macro usually doesn’t care
+about its own name.</p></blockquote></blockquote></blockquote><p>Instead of:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->list</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadr</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">caddr</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadddr</span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr></table></blockquote><p>We can write:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">match</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->list</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">list</span><span class="hspace"> </span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">true-expr</span><span class="RktVal">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">false-expr</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">match: undefined;</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">cannot reference an identifier before its definition</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in module: 'program</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">phase: 1</span></p></td></tr></table></blockquote><p>But wait, we can’t. It’s complaining that <span class="RktSym">match</span> isn’t
+defined. We havne’t required the <span class="RktSym">racket/match</span> module?</p><p>It turns out we haven’t. Remember, this transformer function is
+working at compile time, not run time. And at compile time, only
+<span class="RktSym">racket/base</span> is required for you automatically. If we want
+something like <span class="RktSym">racket/match</span>, we have to require it
+ourselves—<wbr></wbr>and require it <span style="font-style: italic">for compile time</span>. Instead of using
+plain <span class="RktPn">(</span><span class="RktSym">require</span><span class="stt"> </span><span class="RktSym">racket/match</span><span class="RktPn">)</span>, the way to say this is to use
+<span class="RktPn">(</span><span class="RktSym">require</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">for-syntax</span><span class="stt"> </span><span class="RktSym">racket/match</span><span class="RktPn">)</span><span class="RktPn">)</span>—<wbr></wbr>the <span class="RktSym">for-syntax</span>
+part meaning, "for compile time".</p><p>So let’s try that:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">require</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">for-syntax</span><span class="hspace"> </span><span class="RktSym">racket/match</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match-v2</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">match</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->list</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">list</span><span class="hspace"> </span><span class="RktSym">_</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">true-expr</span><span class="RktVal">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">false-expr</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match-v2</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>To review:</p><p>Syntax transformers work at compile time, not run time. The good
+news is this means we can do things like delay evaluation, and
+implement forms like <span class="RktSym">if</span> which simply couldn’t work properly
+as run time functions.</p><p>Some other good news is that there isn’t some special, weird language
+for writing syntax transformers. We can write these transformer
+functions using familiar Racket code. The semi-bad news is that the
+familiarity can make it easy to forget that we’re not working at run
+time. Sometimes that’s important to remember. For example only
+<span class="RktSym">racket/base</span> is required for us automtically. If we need other
+modules, we have to require them, and we have to require them
+<span style="font-style: italic">for compile time</span> using <span class="RktPn">(</span><span class="RktSym">require</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">for-syntax</span><span class="RktPn">)</span><span class="RktPn">)</span>.</p><h3>4<tt> </tt><a name="(part._.Pattern_matching__syntax-case_and_syntax-rules)"></a>Pattern matching: syntax-case and syntax-rules</h3><p>Most useful syntax transformers work by taking some input syntax, and
+rearranging the pieces into something else. As we saw, this is
+possible but tedious using list accessors such as <span class="RktSym">cdddr</span>. It’s
+more convenient and less error-prone to use pattern-matching.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Historically, <span class="RktSym">syntax-case</span> and
+<span class="RktSym">syntax-parse</span> pattern matching came first. <span class="RktSym">match</span> was
+added to Racket later.</p></blockquote></blockquote></blockquote><p>It turns out that pattern-matching was one of the first improvements
+to be added to the Racket macro system. It’s called
+<span class="RktSym">syntax-case</span>, and has a shorthand for simple situations called
+<span class="RktSym">define-syntax-rule</span>.</p><p>Recall our previous example:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym">require</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">for-syntax</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">racket/match</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">our-if-using-match-v2</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">match</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">syntax->list</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">list</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">_</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">condition</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">true-expr</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">false-expr</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">stx</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">`</span><span class="RktPn">(</span><span class="RktSym">cond</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">[</span><span class="RktSym">,</span><span class="RktSym">condition</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">,</span><span class="RktSym">true-expr</span><span class="RktPn">]</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">[</span><span class="RktSym">else</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">,</span><span class="RktSym">false-expr</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote><p>Here’s what it looks like using <span class="RktSym">syntax-case</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-case</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">cond</span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">else</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-case</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>Prety similar, huh? The pattern part looks almost exactly the
+same. The "template" part—<wbr></wbr>where we specify the new syntax—<wbr></wbr>is
+simpler. We don’t need to do quasiquoting and unquoting. We don’t need
+to use <span class="RktSym">datum->syntax</span>. We simply supply a template, which uses
+variables from the pattern.</p><p>There is a shorthand for simple pattern-matching cases, which expands
+into <span class="RktSym">syntax-case</span>. It’s called <span class="RktSym">define-syntax-rule</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax-rule</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-rule</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">cond</span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">else</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-rule</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>Here’s the thing about <span class="RktSym">define-syntax-rule</span>. Because it’s so
+simple, <span class="RktSym">define-syntax-rule</span> is ofen the first thing people are
+taught about macros. But it’s almost deceptively simple. It looks so
+much like defining a normal run time function—<wbr></wbr>yet it’s not. It’s
+working at compile time, not run time. Worse, the moment you want to
+do more than <span class="RktSym">define-syntax-rule</span> can handle, you can fall off
+a cliff into what feels like complicated and confusing
+territory. Hopefully, because we started with a basic syntax
+transformer, and worked up from that, we won’t have that problem. We
+can appreciate <span class="RktSym">define-syntax-rule</span> as a convenient shorthand,
+but not be scared of, or confused about, that for which it’s
+shorthand.</p><h4>4.1<tt> </tt><a name="(part._.Patterns_and_templates)"></a>Patterns and templates</h4><p>Most of the materials I found for learning macros, including the
+Racket Guide, do a very good job explaining how the patterns work. I’m
+not going to regurgitate that here.</p><p>Instead, let’s look at some ways we’re likely to get tripped up.</p><h5>4.1.1<tt> </tt><a name="(part.__.A_pattern_variable_can_t_be_used_outside_of_a_template_)"></a>"A pattern variable can’t be used outside of a template"</h5><p>Let’s say we want to define a function with a hyphenated name, a-b,
+but we supply the a and b parts separately. The Racket <span class="RktSym">struct</span>
+form does somethin like this—<wbr></wbr>if we define a <span class="RktSym">struct</span> named
+<span class="RktSym">foo</span>, it defines a number of functions whose names are
+variations on the name <span class="RktSym">foo</span>, such as <span class="RktSym">foo-field1</span>,
+<span class="RktSym">foo-field2</span>, <span class="RktSym">foo?</span>, and so on.</p><p>So let’s pretend we’re doing something like that. We want to
+transform the syntax <span class="RktPn">(</span><span class="RktSym">hyphen-define</span><span class="stt"> </span><span class="RktSym">a</span><span class="stt"> </span><span class="RktSym">b</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktSym">body</span><span class="RktPn">)</span> to
+the syntax <span class="RktPn">(</span><span class="RktSym">define</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">a-b</span><span class="stt"> </span><span class="RktSym">args</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktSym">body</span><span class="RktPn">)</span>.</p><p>A wrong first attempt is:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">let</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">string->symbol</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktErr">eval:46:0: a: pattern variable cannot be used outside of a</span></p></td></tr><tr><td><p><span class="RktErr">template</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: a</span></p></td></tr></table></blockquote><p>Huh. We have no idea what this error message means. Well, let’s see.
+The "template" is the <span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="stt"> </span><span class="RktSym">args</span><span class="stt"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktSym">body0</span><span class="stt"> </span><span class="RktSym">body</span><span class="stt"> </span><span class="RktSym">...</span><span class="RktPn">)</span> portion. The <span class="RktSym">let</span> isn’t part of that template. It
+sounds like we can’t use <span class="RktSym">a</span> (or <span class="RktSym">b</span>) in the
+<span class="RktSym">let</span> part.</p><p>It turns out we can use a pattern variable in <span style="font-style: italic">another</span>
+pattern—<wbr></wbr>by using <span class="RktSym">syntax-case</span> <span style="font-style: italic">again</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">string->symbol</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktErr">eval:47:0: a: pattern variable cannot be used outside of a</span></p></td></tr><tr><td><p><span class="RktErr">template</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: a</span></p></td></tr></table></blockquote><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>I don’t have a clear explanation for <span style="font-style: italic">why</span> they
+need to be <span class="stt">#</span><span class="stt">’</span><span class="stt">a</span> and <span class="stt">#</span><span class="stt">’</span><span class="stt">b</span>. Can anyone help?</p></blockquote></blockquote></blockquote><p>Well, not quite. We can’t use <span class="RktSym">a</span> and <span class="RktSym">b</span> directly. We
+have to wrap each one in <span class="RktSym">syntax</span>, or use its reader alias,
+<span class="stt">#</span><span class="stt">’</span><span class="stt"></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok1</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktSym">stx</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">string->symbol</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok1</span><span class="hspace"> </span><span class="RktSym">first</span><span class="hspace"> </span><span class="RktSym">second</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">first-second</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#t</span></p></td></tr></table></blockquote><p>And now it works!</p><p>There is a shorthand for using <span class="RktSym">syntax-case</span> this way. It’s
+called <span class="RktSym">with-syntax</span>. This makes it a little simpler:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok2</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">with-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">datum->syntax</span><span class="hspace"> </span><span class="RktSym">stx</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">string->symbol</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#`</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok2</span><span class="hspace"> </span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">bar</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">foo-bar</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#t</span></p></td></tr></table></blockquote><p>Another handy thing is that <span class="RktSym">with-syntax</span> will convert the
+expression to syntax automatically. So we don’t need the
+<span class="RktSym">datum->syntax</span> stuff, and now it becomes even simpler:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok3</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">with-syntax</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">string->symbol</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax->datum</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#`</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym">...</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok3</span><span class="hspace"> </span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">bar</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">foo-bar</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#t</span></p></td></tr></table></blockquote><p>Recap: If you want to munge pattern variables for use in the template,
+<span class="RktSym">with-syntax</span> is your friend. Just remember you have to use
+<span class="RktSym">syntax</span> or <span class="stt">#</span><span class="stt">’</span><span class="stt"></span> on the pattern variables.</p><h3>5<tt> </tt><a name="(part._.Syntax_parameters)"></a>Syntax parameters</h3><p>"Anaphoric if" or "aif" is a popular macro example. Instead of writing:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym">let</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">tmp</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">big-long-calculation</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">if</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">tmp</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">tmp</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">#f</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote><p>It would be great to write:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym">aif</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">big-long-calculation</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">it</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">#f</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote><p>In other words, when the condition is true, an <span class="RktSym">it</span> identifier
+is automatically created and set to the value of the condition. This
+should be easy:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax-rule</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">let</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">it</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">if</span><span class="hspace"> </span><span class="RktSym">it</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">true-expr</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace"> </span><span class="RktSym">it</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">void</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">it: undefined;</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">cannot reference an identifier before its definition</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in module: 'program</span></p></td></tr></table></blockquote><p>Wait, what—<wbr></wbr><span class="RktSym">it</span> is undefined?</p><p>It turns out that all along we have been protected from making a
+certain kind of mistake in our macros. The mistake is to introduce a
+variable that accidentally conflicts with one in the code that is
+using our macro.</p><p>The Racket Reference
+<a href="http://docs.racket-lang.org/reference/syntax-model.html#(part._transformer-model)">Section
+1.2.3.5 Transformer Bindings.</a> has a good explanation of this, and an
+example. (You can stop when you reach the part about set!
+transformers.) Basically, the input syntax has "marks" to preserve
+lexical scope. This makes your macro behave like a normal function. If
+a normal function defines a variable named <span class="RktSym">x</span>, it won’t
+conflict with a variable named <span class="RktSym">x</span> in an outer scope.</p><p>This makes it easy to write reliable macros that behave
+predictably. Unfortunately, once in awhile, we want to introduce a
+magic variable like <span class="RktSym">it</span> for <span class="RktSym">aif</span> on purpose.</p><p>The way to do this is with <span class="RktSym">define-syntax-parameter</span> and
+<span class="RktSym">syntax-parameterize</span>. You’re probably familiar with regular
+parameters in Racket.</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktSym">current-foo</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">make-parameter</span><span class="hspace"> </span><span class="RktVal">"some default value"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">current-foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"some default value"</span></p></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">parameterize</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">current-foo</span><span class="hspace"> </span><span class="RktVal">"I have a new value, for now"</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">current-foo</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktRes">"I have a new value, for now"</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">current-foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"some default value"</span></p></td></tr></table></blockquote><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Historically, there are other ways to do this. If you
+know them, you will want to unlearn them. But if you’re the target
+audience I’m writing for, you don’t know them yet. You can skip
+learning them now. (Someday if you want to understand someone else’s
+older macros, you can learn about them then.)</p></blockquote></blockquote></blockquote><p>The syntax variation of them works similarly. The idea is, we’ll
+define <span class="RktSym">it</span> to mean an error by default. Only inside of our
+<span class="RktSym">aif</span> will it have a meaningful value:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">require</span><span class="hspace"> </span><span class="RktSym">racket/stxparam</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax-parameter</span><span class="hspace"> </span><span class="RktSym">it</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">raise-syntax-error</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-e</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">"can only be used inside aif"</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define-syntax-rule</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">let</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">tmp</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">if</span><span class="hspace"> </span><span class="RktSym">tmp</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">syntax-parameterize</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">it</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">make-rename-transformer</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">tmp</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktVal">10</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace"> </span><span class="RktSym">it</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">void</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">10</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktVal">#f</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace"> </span><span class="RktSym">it</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">void</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>We can still use <span class="RktSym">it</span> as a normal variable name:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace"> </span><span class="RktSym">it</span><span class="hspace"> </span><span class="RktVal">10</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktSym">it</span></td></tr><tr><td><p><span class="RktRes">10</span></p></td></tr></table></blockquote><p>If we try to use <span class="RktSym">it</span> outside of an <span class="RktSym">aif</span> form, and
+<span class="RktSym">it</span> isn’t otherwise defined, we get an error like we want:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace"> </span><span class="RktSym">it</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">10</span></p></td></tr></table></blockquote><p>Perfect.</p><h3>6<tt> </tt><a name="(part._.Robust_macros__syntax-parse)"></a>Robust macros: syntax-parse</h3><p>TO-DO.</p><h3>7<tt> </tt><a name="(part._.Other_questions)"></a>Other questions</h3><p>Hopefully I will answer these in the course of the other sections. But
+just in case:</p><h4>7.1<tt> </tt><a name="(part._.What_s_the_point_of_with-syntax_)"></a>What’s the point of <span class="RktSym">with-syntax</span>?</h4><p>Done.</p><h4>7.2<tt> </tt><a name="(part._.What_s_the_point_of_begin-for-syntax_)"></a>What’s the point of <span class="RktSym">begin-for-syntax</span>?</h4><p>TO-DO.</p><h4>7.3<tt> </tt><a name="(part._.What_s_the_point_of_racket_splicing_)"></a>What’s the point of <span class="RktSym">racket/splicing</span>?</h4><p>TO-DO.</p><h3>8<tt> </tt><a name="(part._.References_.Acknowledgements)"></a>References/Acknowledgements</h3><p>Eli Barzliay wrote a blog post,
+ <a href="http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html">Writing
+‘syntax-case’ Macros</a>, which explains many key details. However it’s written
+especially for people already familiar with "un-hygienic" "defmacro"
+style macros. If you’re not familiar with those, it may seem slightly
+weird to the extent it’s trying to convince you to change an opinion
+you don’t have. Even so, many key details are presented in Eli’s typically
+concise, clear fashion.</p><p>Eli Barzilay wrote another blog post,
+<a href="http://blog.racket-lang.org/2008/02/dirty-looking-hygiene.html">Dirty
+Looking Hygiene</a>, which explains syntax-parameterize. I relied
+heavily on that, mostly just updating it since his post was written
+before PLT Scheme was renamed to Racket.</p><h3>9<tt> </tt><a name="(part._.Epilog)"></a>Epilog</h3><blockquote class="SCentered"><p>"Before I had studied Chan (Zen) for thirty years, I saw mountains as
+mountains, and rivers as rivers. When I arrived at a more intimate
+knowledge, I came to the point where I saw that mountains are not
+mountains, and rivers are not rivers. But now that I have got its very
+substance I am at rest. For it’s just that I see mountains once again
+as mountains, and rivers once again as rivers"</p><p><span class="Smaller">–Buddhist saying originally formulated by Qingyuan Weixin,
+later translated by D.T. Suzuki in his <span style="font-style: italic">Essays in Zen
+Buddhism</span>.</span></p></blockquote><p>Translated into Racket:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym">dynamic-wind</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">and</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">mountains</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">mountains</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">rivers</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">rivers</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">not</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">and</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">mountains</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">mountains</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">rivers</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">rivers</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">and</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">mountains</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">mountains</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">rivers</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">rivers</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></blockquote></div></div><div id="contextindicator"> </div></body></html>
+\ No newline at end of file
diff --git a/main.rkt b/main.rkt
@@ -0,0 +1,818 @@
+#lang scribble/manual
+
+@(require racket/sandbox
+ scribble/eval)
+@(define evaluator
+ (parameterize ([sandbox-output 'string]
+ [sandbox-error-output 'string])
+ (make-evaluator 'racket)))
+
+@(define-syntax-rule (i body ...)
+ (interaction #:eval evaluator body ...))
+
+@title{Fear of Macros}
+
+@smaller{Copyright (c) 2012 by Greg Hendershott. All rights reserved.}
+
+@table-of-contents{}
+
+
+@; ----------------------------------------------------------------------------
+
+@section{Introduction}
+
+I learned Racket after 25 years of doing C/C++ imperative programming.
+
+Some psychic whiplash resulted.
+
+"All the parentheses" was actually not a big deal. Instead, the first
+mind warp was functional programming. Before long I wrapped my brain
+around it, and went on to become comfortable and effective with many
+other aspects and features of Racket.
+
+But two final frontiers remained: Macros and continuations.
+
+I found that simple macros were easy and understandable, plus there
+were many good tutorials available. But the moment I stepped past
+routine pattern-matching, I kind of fell off a cliff into a
+terminology soup. I marinaded myself in material, hoping it would
+eventually sink in after enough re-readings. I even found myself using
+trial and error, rather than having a clear mental model what was
+going on. Gah.
+
+I'm starting to write this at the point where the shapes are slowly
+emerging from the fog.
+
+My primary motive is selfish. Explaining something forces me to learn
+it more thorougly. Plus I expect that if I write something with
+mistakes, other people will be eager to point them out and correct
+me. Is that a social-engineering variation of meta-programming? Next
+question, please. :)
+
+Finally I do hope it may help other people who have a similar
+background and/or learning style as me.
+
+I want to show how Racket macro features have evolved as solutions to
+problems or annoyances. I learn more quickly and deeply when I
+discover the answer to a question I already have, or find the solution
+to a problem whose pain I already feel. Therefore I'll give you the
+questions and problems first, so that you can better appreciate and
+understand the answers and solutions.
+
+@; ----------------------------------------------------------------------------
+
+@section{The plan of attack}
+
+The macro system you will mostly want to use for production-quality
+macros is called @racket[syntax-parse]. And don't worry, we'll get to
+that soon.
+
+But if we start there, you're likely to feel overwhelmed by concepts
+and terminology, and get very confused. I did.
+
+1. Instead let's start with the basics: A syntax object and a function
+to change it (a "transformer"). We'll work at that level for awhile to
+get comfortable and to de-mythologize this whole macro business.
+
+2. Next, we'll realize that some pattern-matching would make life
+easier. We'll learn about @racket[syntax-case], and its shorthand
+cousin, @racket[define-syntax-rule]. We'll discover we can get
+confused if we want to munge pattern variables before sticking them
+back in the template, and learn how to do that.
+
+3. At this point we'll be able to write many useful macros. But, what
+if we want to write the ever-popular anaphoric if, with a "magic
+variable"? It turns out we've been protected from making certain kind
+of mistakes. When we want to do this kind of thing on purpose, we use
+a @racket[syntax parameter]. [There are other, older ways to do
+this. We won't look at them. We also won't spend a lot of time talking
+about "hygiene".]
+
+4. Finally, we'll realize that our macros could be smarter when
+they're used in error. Normal Racket functions can optionally have
+contracts and types. These can catch mistakes and provide clear,
+useful error messages. It would be great if there were somthing
+similar for macros, and there is. One of the more-recent Racket macro
+enhancements is @racket[syntax-parse].
+
+
+@; ----------------------------------------------------------------------------
+
+@section{Transformers}
+
+@verbatim[#:indent 2]{
+YOU ARE INSIDE A ROOM.
+THERE ARE KEYS ON THE GROUND.
+THERE IS A SHINY BRASS LAMP NEARBY.
+
+IF YOU GO THE WRONG WAY, YOU WILL BECOME
+HOPELESSLY LOST AND CONFUSED.
+
+> pick up the keys
+
+YOU HAVE A SYNTAX TRANSFORMER
+}
+
+
+@subsection{What is a syntax transformer?}
+
+A syntax transformer is not one of the トランスフォーマ
+@hyperlink["http://en.wikipedia.org/wiki/Transformers" "transformers"].
+
+Instead, it is quite simple. It is a function. The function takes
+syntax and returns syntax. It transforms syntax.
+
+Here's a transformer function that ignores its input syntax, and
+always outputs syntax for a string literal:
+
+@i[
+(define-syntax foo
+ (lambda (stx)
+ (syntax "I am foo")))
+(foo)
+]
+
+When we use @racket[define-syntax], we're making a transformer
+@italic{binding}. This tells the Racket compiler, "Whenever you
+encounter a chunk of syntax starting with @racket[foo], please give it
+to my transformer function, and replace it with the syntax I give back
+to you." So Racket will give anything that looks like @racket[(foo
+...)] to our function, and we can change it. Much like a
+search-and-replace.
+
+Maybe you know that the usual way to define a function in Racket:
+
+@racket[(define (f x) ...)]
+
+is shorthand for:
+
+@racket[(define f (lambda (x) ...))]
+
+That shorthand lets you avoid typing @racket[lambda] and some parentheses.
+
+Well there is a similar shorthand for @racket[define-syntax]:
+
+@i[
+(define-syntax (also-foo stx)
+ (syntax "I am also foo"))
+(also-foo)
+]
+
+What we want to remember is that this is simply shorthand. We are
+still defining a transformer function, which takes syntax and returns
+syntax. Everything we do with macros, will be built on top of this
+basic idea. It's not magic.
+
+Speaking of shorthand, there is also a shorthand for @racket[syntax],
+which is @tt{#'}:
+
+@i[
+(define-syntax (quoted-foo stx)
+ #'"I am also foo, using #' instead of syntax")
+(quoted-foo)
+]
+
+Of course, we can emit syntax that is more interesting than a
+string literal. How about returning @racket[(displayln "hi")]?
+
+@i[
+(define-syntax (say-hi stx)
+ #'(displayln "hi"))
+(say-hi)
+]
+
+When Racket expands our program, it sees the occurrence of
+@racket[(say-hi)], and sees it has a transformer function for that. It
+calls our function with the old syntax, and we return the new syntax,
+which is used to evaluate and run our program.
+
+
+@subsection{What is the input?}
+
+Our examples so far have been ignoring the input syntax, and
+outputting a fixed syntax. Usually, we want to transform the input to
+something else.
+
+But let's start by looking at what the input @italic{is}:
+
+@i[
+(define-syntax (show-me stx)
+ (print stx)
+ #'(void))
+(show-me '(i am a list))
+]
+
+The @racket[(print stx)] shows what our transformer is given: a syntax
+object.
+
+A syntax object consists of several things. The first part is the
+s-expression representing the code, such as @racket['(i am a
+list)]. Racket (and Scheme and Lisp) expressions are s-expressions---
+code and data have the same structure, and this makes it vastly easier
+to rewrite syntax, i.e. write macros.
+
+Racket syntax is also decorated with some interesting information such
+as the source file, line number, and column. Finally, it has
+information about lexical scoping (which you don't need to worry about
+now, but will turn out to be important later.)
+
+There are a variety of functions available to access a syntax object:
+
+@i[
+(define stx #'(if x (list "true") #f))
+(syntax->datum stx)
+(syntax-e stx)
+(syntax->list stx)
+(syntax-source stx)
+(syntax-line stx)
+(syntax-column stx)
+]
+
+When we want to transform syntax, we'll generally take the pieces we
+were given, maybe rearrange their order, perhaps change some of the
+pieces, and often introduce brand-new pieces.
+
+@subsection{Actually transforming the input}
+
+Let's write a transformer function that reverses the syntax it was
+given:
+
+@i[
+(define-syntax (reverse-me stx)
+ (datum->syntax stx (reverse (cdr (syntax->datum stx)))))
+(reverse-me "backwards" "am" "i" values)
+]
+
+What's going on here? First we take the input syntax, and give it to
+@racket[syntax->datum]. This converts the syntax into a plain old list:
+
+@i[
+(syntax->datum #'(reverse-me "backwards" "am" "i" values))
+]
+
+Using @racket[cdr] slics off the first item of the list,
+@racket[reverse-me], leaving the rmainder:
+@racket[("backwards" "am" "i" values)]. Passing that to
+@racket[reverse] changes it to @racket[(values "i" "am" "backwards")]:
+
+@i[
+(reverse (cdr '("backwards" "am" "i" values)))
+]
+
+Finally we use @racket[syntax->datum] to convert this back to
+@racket[syntax]:
+
+@i[
+(datum->syntax #f '(values "i" "am" "backwards"))
+]
+
+That's what our transformer function gives back to the Racket
+compiler, and @italic{that} syntax is evaluated:
+
+@i[
+(values "i" "am" "backwards")
+]
+
+
+@subsection{Compile time vs. run time}
+
+Normal Racket code runs at ... run time. Duh.
+
+@margin-note{Instead of "compile time vs. run time", you may hear it
+described as "syntax phase vs. runtime phase". Same difference.}
+
+But a syntax transformer is run by the Racket compiler, as part of the
+process of parsing, expanding and understanding your code. In other
+words, your syntax transformer function is evaluated at compile time.
+
+This aspect of macros lets you do things that simply aren't possible
+in normal code. One of the classic examples, is something like the
+Racket @racket[if] form:
+
+@racket[(if <condition> <true-expression> <false-expression>)]
+
+If @racket[if] were implemented as a function, all of the arguments
+would be evaluated before being provided to the function.
+
+@i[
+(define (our-if condition true-expr false-expr)
+ (cond [condition true-expr]
+ [else false-expr]))
+(our-if #t
+ "true"
+ "false")
+]
+
+That seems to work. However, how about this:
+
+@i[
+(define (display-and-return x)
+ (displayln x)
+ x)
+(our-if #t
+ (display-and-return "true")
+ (display-and-return "false"))
+]
+
+@margin-note{One answer is that functional programming is good, and
+side-effects are bad. But avoiding side-effects isn't always
+practical.}
+
+Oops. Because the expressions have a side-effect, it's obvious that
+they are both evaluated. And that could be a problem---what if the
+side-effect includes deleting a file on disk? You wouldn't want
+@racket[(if user-wants-file-deleted? (delete-file) (void))] to delete
+a file even when @racket[user-wants-file-deleted?] is @racket[#f].
+
+So this simply can't work as a plain function. However a syntax
+transformer can rearrange the syntax -- rewrite the code -- at compile
+time. The pieces of syntax are moved around, but they aren't actually
+evaluated until run time.
+
+Here is one way to do this:
+
+@i[
+(define-syntax (our-if-v2 stx)
+ (define xs (syntax->list stx))
+ (datum->syntax stx `(cond [,(cadr xs) ,(caddr xs)]
+ [else ,(cadddr xs)])))
+(our-if-v2 #t
+ (display-and-return "true")
+ (display-and-return "false"))
+(our-if-v2 #f
+ (display-and-return "true")
+ (display-and-return "false"))
+]
+
+That gave the right answer. But how? Let's pull out the transformer
+function itself, and see what it did. We start with an example of some
+input syntax:
+
+@i[
+(define stx (syntax (our-if-v2 #t "true" "false")))
+(displayln stx)
+]
+
+1. We take the original syntax, and use @racket[syntax->datum] to
+change it into a plain Racket @racket[list]:
+
+@i[
+(define xs (syntax->datum stx))
+(displayln xs)
+]
+
+2. To change this into a Racket @racket[cond] form, we need to take
+the three interesting pieces---the condition, true-expression, and
+false-expression---from the list using @racket[cadr], @racket[caddr],
+and @racket[cadddr] and arrange them into a @racket[cond] form:
+
+@codeblock{
+`(cond [,(cadr xs) ,(caddr xs)]
+ [else ,(cadddr xs)])
+}
+
+3. Finally, we change that into @racket[syntax] using
+@racket[datum->syntax]:
+
+@i[
+(datum->syntax stx `(cond [,(cadr xs) ,(caddr xs)]
+ [else ,(cadddr xs)]))
+]
+
+So that works, but using @racket[cdddr] etc. to destructure a list is
+painful and error-prone. Maybe you know Racket's @racket[match]?
+Using that would let us do pattern-matching.
+
+@margin-note{Notice that we don't care about the first item in the
+syntax list. We didn't take @racket[(car xs)] in our-if-v2, and we
+didn't use @racket[name] when we used pattern-matching. In general, a
+syntax transformer won't care about that, because it is the name of
+the transformer binding. In other words, a macro usually doesn't care
+about its own name.}
+
+Instead of:
+
+@i[
+(define-syntax (our-if-v2 stx)
+ (define xs (syntax->list stx))
+ (datum->syntax stx `(cond [,(cadr xs) ,(caddr xs)]
+ [else ,(cadddr xs)])))
+]
+
+We can write:
+
+@i[
+(define-syntax (our-if-using-match stx)
+ (match (syntax->list stx)
+ [(list name condition true-expr false-expr)
+ (datum->syntax stx `(cond [,condition ,true-expr]
+ [else ,false-expr]))]))
+(our-if-using-match #t "true" "false")
+]
+
+But wait, we can't. It's complaining that @racket[match] isn't
+defined. We havne't required the @racket[racket/match] module?
+
+It turns out we haven't. Remember, this transformer function is
+working at compile time, not run time. And at compile time, only
+@racket[racket/base] is required for you automatically. If we want
+something like @racket[racket/match], we have to require it
+ourselves---and require it @italic{for compile time}. Instead of using
+plain @racket[(require racket/match)], the way to say this is to use
+@racket[(require (for-syntax racket/match))]---the @racket[for-syntax]
+part meaning, "for compile time".
+
+So let's try that:
+
+@i[
+(require (for-syntax racket/match))
+(define-syntax (our-if-using-match-v2 stx)
+ (match (syntax->list stx)
+ [(list _ condition true-expr false-expr)
+ (datum->syntax stx `(cond [,condition ,true-expr]
+ [else ,false-expr]))]))
+(our-if-using-match-v2 #t "true" "false")
+]
+
+To review:
+
+Syntax transformers work at compile time, not run time. The good
+news is this means we can do things like delay evaluation, and
+implement forms like @racket[if] which simply couldn't work properly
+as run time functions.
+
+Some other good news is that there isn't some special, weird language
+for writing syntax transformers. We can write these transformer
+functions using familiar Racket code. The semi-bad news is that the
+familiarity can make it easy to forget that we're not working at run
+time. Sometimes that's important to remember. For example only
+@racket[racket/base] is required for us automtically. If we need other
+modules, we have to require them, and we have to require them
+@italic{for compile time} using @racket[(require (for-syntax))].
+
+@; ----------------------------------------------------------------------------
+
+@section{Pattern matching: syntax-case and syntax-rules}
+
+Most useful syntax transformers work by taking some input syntax, and
+rearranging the pieces into something else. As we saw, this is
+possible but tedious using list accessors such as @racket[cdddr]. It's
+more convenient and less error-prone to use pattern-matching.
+
+@margin-note{Historically, @racket[syntax-case] and
+@racket[syntax-parse] pattern matching came first. @racket[match] was
+added to Racket later.}
+
+It turns out that pattern-matching was one of the first improvements
+to be added to the Racket macro system. It's called
+@racket[syntax-case], and has a shorthand for simple situations called
+@racket[define-syntax-rule].
+
+Recall our previous example:
+
+@codeblock{
+(require (for-syntax racket/match))
+(define-syntax (our-if-using-match-v2 stx)
+ (match (syntax->list stx)
+ [(list _ condition true-expr false-expr)
+ (datum->syntax stx `(cond [,condition ,true-expr]
+ [else ,false-expr]))]))
+}
+
+Here's what it looks like using @racket[syntax-case]:
+
+@i[
+(define-syntax (our-if-using-syntax-case stx)
+ (syntax-case stx ()
+ [(_ condition true-expr false-expr)
+ #'(cond [condition true-expr]
+ [else false-expr])]))
+(our-if-using-syntax-case #t "true" "false")
+]
+
+Prety similar, huh? The pattern part looks almost exactly the
+same. The "template" part---where we specify the new syntax---is
+simpler. We don't need to do quasiquoting and unquoting. We don't need
+to use @racket[datum->syntax]. We simply supply a template, which uses
+variables from the pattern.
+
+There is a shorthand for simple pattern-matching cases, which expands
+into @racket[syntax-case]. It's called @racket[define-syntax-rule]:
+
+@i[
+(define-syntax-rule (our-if-using-syntax-rule condition true-expr false-expr)
+ (cond [condition true-expr]
+ [else false-expr]))
+(our-if-using-syntax-rule #t "true" "false")
+]
+
+Here's the thing about @racket[define-syntax-rule]. Because it's so
+simple, @racket[define-syntax-rule] is ofen the first thing people are
+taught about macros. But it's almost deceptively simple. It looks so
+much like defining a normal run time function---yet it's not. It's
+working at compile time, not run time. Worse, the moment you want to
+do more than @racket[define-syntax-rule] can handle, you can fall off
+a cliff into what feels like complicated and confusing
+territory. Hopefully, because we started with a basic syntax
+transformer, and worked up from that, we won't have that problem. We
+can appreciate @racket[define-syntax-rule] as a convenient shorthand,
+but not be scared of, or confused about, that for which it's
+shorthand.
+
+@subsection{Patterns and templates}
+
+Most of the materials I found for learning macros, including the
+Racket Guide, do a very good job explaining how the patterns work. I'm
+not going to regurgitate that here.
+
+Instead, let's look at some ways we're likely to get tripped up.
+
+@subsubsection{"A pattern variable can't be used outside of a template"}
+
+Let's say we want to define a function with a hyphenated name, a-b,
+but we supply the a and b parts separately. The Racket @racket[struct]
+form does somethin like this---if we define a @racket[struct] named
+@racket[foo], it defines a number of functions whose names are
+variations on the name @racket[foo], such as @racket[foo-field1],
+@racket[foo-field2], @racket[foo?], and so on.
+
+So let's pretend we're doing something like that. We want to
+transform the syntax @racket[(hyphen-define a b (args) body)] to
+the syntax @racket[(define (a-b args) body)].
+
+A wrong first attempt is:
+
+@i[
+(define-syntax (hyphen-define/wrong stx)
+ (syntax-case stx ()
+ [(_ a b (args ...) body0 body ...)
+ (let ([name (string->symbol (format "~a-~a" a b))])
+ #'(define (name args ...)
+ body0 body ...))]))
+]
+
+Huh. We have no idea what this error message means. Well, let's see.
+The "template" is the @racket[#'(define (name args ...) body0 body
+...)] portion. The @racket[let] isn't part of that template. It
+sounds like we can't use @racket[a] (or @racket[b]) in the
+@racket[let] part.
+
+It turns out we can use a pattern variable in @italic{another}
+pattern---by using @racket[syntax-case] @italic{again}:
+
+@i[
+(define-syntax (hyphen-define/wrong stx)
+ (syntax-case stx ()
+ [(_ a b (args ...) body0 body ...)
+ (syntax-case (datum->syntax stx (string->symbol (format "~a-~a"
+ (syntax->datum a)
+ (syntax->datum b)))) ()
+ [name #'(define (name args ...)
+ body0 body ...)])]))
+]
+
+@margin-note{I don't have a clear explanation for @italic{why} they
+need to be @tt{#'a} and @tt{#'b}. Can anyone help?}
+
+Well, not quite. We can't use @racket[a] and @racket[b] directly. We
+have to wrap each one in @racket[syntax], or use its reader alias,
+@tt{#'}:
+
+@i[
+(define-syntax (hyphen-define/ok1 stx)
+ (syntax-case stx ()
+ [(_ a b (args ...) body0 body ...)
+ (syntax-case (datum->syntax stx
+ (string->symbol (format "~a-~a"
+ (syntax->datum #'a)
+ (syntax->datum #'b)))) ()
+ [name #'(define (name args ...)
+ body0 body ...)])]))
+(hyphen-define/ok1 first second () #t)
+(first-second)
+]
+
+And now it works!
+
+There is a shorthand for using @racket[syntax-case] this way. It's
+called @racket[with-syntax]. This makes it a little simpler:
+
+@i[
+(define-syntax (hyphen-define/ok2 stx)
+ (syntax-case stx ()
+ [(_ a b (args ...) body0 body ...)
+ (with-syntax ([name (datum->syntax stx
+ (string->symbol (format "~a-~a"
+ (syntax->datum #'a)
+ (syntax->datum #'b))))])
+ #`(define (name args ...)
+ body0 body ...))]))
+(hyphen-define/ok2 foo bar () #t)
+(foo-bar)
+]
+
+Another handy thing is that @racket[with-syntax] will convert the
+expression to syntax automatically. So we don't need the
+@racket[datum->syntax] stuff, and now it becomes even simpler:
+
+@i[
+(define-syntax (hyphen-define/ok3 stx)
+ (syntax-case stx ()
+ [(_ a b (args ...) body0 body ...)
+ (with-syntax ([name (string->symbol (format "~a-~a"
+ (syntax->datum #'a)
+ (syntax->datum #'b)))])
+ #`(define (name args ...)
+ body0 body ...))]))
+(hyphen-define/ok3 foo bar () #t)
+(foo-bar)
+]
+
+Recap: If you want to munge pattern variables for use in the template,
+@racket[with-syntax] is your friend. Just remember you have to use
+@racket[syntax] or @tt{#'} on the pattern variables.
+
+@; ----------------------------------------------------------------------------
+
+@section{Syntax parameters}
+
+"Anaphoric if" or "aif" is a popular macro example. Instead of writing:
+
+@codeblock{
+(let ([tmp (big-long-calculation)])
+ (if tmp
+ (foo tmp)
+ #f))
+}
+
+It would be great to write:
+
+@codeblock{
+(aif (big-long-calculation)
+ (foo it)
+ #f)
+}
+
+In other words, when the condition is true, an @racket[it] identifier
+is automatically created and set to the value of the condition. This
+should be easy:
+
+
+@i[
+(define-syntax-rule (aif condition true-expr false-expr)
+ (let ([it condition])
+ (if it
+ true-expr
+ false-expr)))
+(aif #t (displayln it) (void))
+]
+
+Wait, what---@racket[it] is undefined?
+
+It turns out that all along we have been protected from making a
+certain kind of mistake in our macros. The mistake is to introduce a
+variable that accidentally conflicts with one in the code that is
+using our macro.
+
+The Racket Reference
+@hyperlink["http://docs.racket-lang.org/reference/syntax-model.html#(part._transformer-model)" "Section
+1.2.3.5 Transformer Bindings."] has a good explanation of this, and an
+example. (You can stop when you reach the part about set!
+transformers.) Basically, the input syntax has "marks" to preserve
+lexical scope. This makes your macro behave like a normal function. If
+a normal function defines a variable named @racket[x], it won't
+conflict with a variable named @racket[x] in an outer scope.
+
+This makes it easy to write reliable macros that behave
+predictably. Unfortunately, once in awhile, we want to introduce a
+magic variable like @racket[it] for @racket[aif] on purpose.
+
+The way to do this is with @racket[define-syntax-parameter] and
+@racket[syntax-parameterize]. You're probably familiar with regular
+parameters in Racket.
+
+@i[
+(define current-foo (make-parameter "some default value"))
+(current-foo)
+(parameterize ([current-foo "I have a new value, for now"])
+ (current-foo))
+(current-foo)
+]
+
+@margin-note{Historically, there are other ways to do this. If you
+know them, you will want to unlearn them. But if you're the target
+audience I'm writing for, you don't know them yet. You can skip
+learning them now. (Someday if you want to understand someone else's
+older macros, you can learn about them then.)}
+
+The syntax variation of them works similarly. The idea is, we'll
+define @racket[it] to mean an error by default. Only inside of our
+@racket[aif] will it have a meaningful value:
+
+@i[
+(require racket/stxparam)
+(define-syntax-parameter it
+ (lambda (stx)
+ (raise-syntax-error (syntax-e stx) "can only be used inside aif")))
+(define-syntax-rule (aif condition true-expr false-expr)
+ (let ([tmp condition])
+ (if tmp
+ (syntax-parameterize ([it (make-rename-transformer #'tmp)])
+ true-expr)
+ false-expr)))
+(aif 10 (displayln it) (void))
+(aif #f (displayln it) (void))
+]
+
+We can still use @racket[it] as a normal variable name:
+
+@i[
+(define it 10)
+it
+]
+
+If we try to use @racket[it] outside of an @racket[aif] form, and
+@racket[it] isn't otherwise defined, we get an error like we want:
+
+@i[
+(displayln it)
+]
+
+Perfect.
+
+@; ----------------------------------------------------------------------------
+
+@section{Robust macros: syntax-parse}
+
+TO-DO.
+
+@; ----------------------------------------------------------------------------
+
+@section{Other questions}
+
+Hopefully I will answer these in the course of the other sections. But
+just in case:
+
+@subsection{What's the point of @racket[with-syntax]?}
+
+Done.
+
+@subsection{What's the point of @racket[begin-for-syntax]?}
+
+TO-DO.
+
+@subsection{What's the point of @racket[racket/splicing]?}
+
+TO-DO.
+
+@; ----------------------------------------------------------------------------
+
+@section{References/Acknowledgements}
+
+Eli Barzliay wrote a blog post,
+ @hyperlink["http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html" "Writing
+‘syntax-case’ Macros"], which explains many key details. However it's written
+especially for people already familiar with "un-hygienic" "defmacro"
+style macros. If you're not familiar with those, it may seem slightly
+weird to the extent it's trying to convince you to change an opinion
+you don't have. Even so, many key details are presented in Eli's typically
+concise, clear fashion.
+
+Eli Barzilay wrote another blog post,
+@hyperlink["http://blog.racket-lang.org/2008/02/dirty-looking-hygiene.html" "Dirty
+Looking Hygiene"], which explains syntax-parameterize. I relied
+heavily on that, mostly just updating it since his post was written
+before PLT Scheme was renamed to Racket.
+
+@; ----------------------------------------------------------------------------
+
+@section{Epilog}
+
+@centered{
+"Before I had studied Chan (Zen) for thirty years, I saw mountains as
+mountains, and rivers as rivers. When I arrived at a more intimate
+knowledge, I came to the point where I saw that mountains are not
+mountains, and rivers are not rivers. But now that I have got its very
+substance I am at rest. For it's just that I see mountains once again
+as mountains, and rivers once again as rivers"
+
+@smaller{--Buddhist saying originally formulated by Qingyuan Weixin,
+later translated by D.T. Suzuki in his @italic{Essays in Zen
+Buddhism}.}
+}
+
+
+Translated into Racket:
+
+@codeblock{
+(dynamic-wind (lambda ()
+ (and (eq? 'mountains 'mountains)
+ (eq? 'rivers 'rivers)))
+ (lambda ()
+ (not (and (eq? 'mountains 'mountains)
+ (eq? 'rivers 'rivers))))
+ (lambda ()
+ (and (eq? 'mountains 'mountains)
+ (eq? 'rivers 'rivers))))
+}
+
diff --git a/racket.css b/racket.css
@@ -0,0 +1,233 @@
+
+/* See the beginning of "scribble.css". */
+
+/* Monospace: */
+.RktIn, .RktRdr, .RktPn, .RktMeta,
+.RktMod, .RktKw, .RktVar, .RktSym,
+.RktRes, .RktOut, .RktCmt, .RktVal {
+ font-family: monospace;
+ white-space: inherit;
+}
+
+/* Serif: */
+.inheritedlbl {
+ font-family: serif;
+}
+
+/* Sans-serif: */
+.RBackgroundLabelInner {
+ font-family: sans-serif;
+}
+
+/* ---------------------------------------- */
+/* Inherited methods, left margin */
+
+.inherited {
+ width: 100%;
+ margin-top: 0.5em;
+ text-align: left;
+ background-color: #ECF5F5;
+}
+
+.inherited td {
+ font-size: 82%;
+ padding-left: 1em;
+ text-indent: -0.8em;
+ padding-right: 0.2em;
+}
+
+.inheritedlbl {
+ font-style: italic;
+}
+
+/* ---------------------------------------- */
+/* Racket text styles */
+
+.RktIn {
+ color: #cc6633;
+ background-color: #eeeeee;
+}
+
+.RktInBG {
+ background-color: #eeeeee;
+}
+
+.RktRdr {
+}
+
+.RktPn {
+ color: #843c24;
+}
+
+.RktMeta {
+ color: black;
+}
+
+.RktMod {
+ color: black;
+}
+
+.RktOpt {
+ color: black;
+}
+
+.RktKw {
+ color: black;
+ /* font-weight: bold; */
+}
+
+.RktErr {
+ color: red;
+ font-style: italic;
+}
+
+.RktVar {
+ color: #262680;
+ font-style: italic;
+}
+
+.RktSym {
+ color: #262680;
+}
+
+.RktValLink {
+ text-decoration: none;
+ color: blue;
+}
+
+.RktModLink {
+ text-decoration: none;
+ color: blue;
+}
+
+.RktStxLink {
+ text-decoration: none;
+ color: black;
+ /* font-weight: bold; */
+}
+
+.RktRes {
+ color: #0000af;
+}
+
+.RktOut {
+ color: #960096;
+}
+
+.RktCmt {
+ color: #c2741f;
+}
+
+.RktVal {
+ color: #228b22;
+}
+
+/* ---------------------------------------- */
+/* Some inline styles */
+
+.together {
+ width: 100%;
+}
+
+.prototype, .argcontract, .RBoxed {
+ white-space: nowrap;
+}
+
+.prototype td {
+ vertical-align: text-top;
+}
+.longprototype td {
+ vertical-align: bottom;
+}
+
+.RktBlk {
+ white-space: inherit;
+ text-align: left;
+}
+
+.RktBlk tr {
+ white-space: inherit;
+}
+
+.RktBlk td {
+ vertical-align: baseline;
+ white-space: inherit;
+}
+
+.argcontract td {
+ vertical-align: text-top;
+}
+
+.highlighted {
+ background-color: #ddddff;
+}
+
+.defmodule {
+ width: 100%;
+ background-color: #F5F5DC;
+}
+
+.specgrammar {
+ float: right;
+}
+
+.RBibliography td {
+ vertical-align: text-top;
+}
+
+.leftindent {
+ margin-left: 1em;
+ margin-right: 0em;
+}
+
+.insetpara {
+ margin-left: 1em;
+ margin-right: 1em;
+}
+
+.Rfilebox {
+}
+
+.Rfiletitle {
+ text-align: right;
+ margin: 0em 0em 0em 0em;
+}
+
+.Rfilename {
+ border-top: 1px solid #6C8585;
+ border-right: 1px solid #6C8585;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ background-color: #ECF5F5;
+}
+
+.Rfilecontent {
+ margin: 0em 0em 0em 0em;
+}
+
+/* ---------------------------------------- */
+/* For background labels */
+
+.RBackgroundLabel {
+ float: right;
+ width: 0px;
+ height: 0px;
+}
+
+.RBackgroundLabelInner {
+ position: relative;
+ width: 25em;
+ left: -25.5em;
+ top: 0px;
+ text-align: right;
+ color: white;
+ z-index: 0;
+ font-weight: bold;
+}
+
+.RForeground {
+ position: relative;
+ left: 0px;
+ top: 0px;
+ z-index: 1;
+}
diff --git a/scribble-common.js b/scribble-common.js
@@ -0,0 +1,153 @@
+// Common functionality for PLT documentation pages
+
+// Page Parameters ------------------------------------------------------------
+
+var page_query_string =
+ (location.href.search(/\?([^#]+)(?:#|$)/) >= 0) && RegExp.$1;
+
+var page_args =
+ ((function(){
+ if (!page_query_string) return [];
+ var args = page_query_string.split(/[&;]/);
+ for (var i=0; i<args.length; i++) {
+ var a = args[i];
+ var p = a.indexOf('=');
+ if (p >= 0) args[i] = [a.substring(0,p), a.substring(p+1)];
+ else args[i] = [a, false];
+ }
+ return args;
+ })());
+
+function GetPageArg(key, def) {
+ for (var i=0; i<page_args.length; i++)
+ if (page_args[i][0] == key) return unescape(page_args[i][1]);
+ return def;
+}
+
+function MergePageArgsIntoLink(a) {
+ if (page_args.length == 0 ||
+ (!a.attributes["pltdoc"]) || (a.attributes["pltdoc"].value == ""))
+ return;
+ a.href.search(/^([^?#]*)(?:\?([^#]*))?(#.*)?$/);
+ if (RegExp.$2.length == 0) {
+ a.href = RegExp.$1 + "?" + page_query_string + RegExp.$3;
+ } else {
+ // need to merge here, precedence to arguments that exist in `a'
+ var i, j;
+ var prefix = RegExp.$1, str = RegExp.$2, suffix = RegExp.$3;
+ var args = str.split(/[&;]/);
+ for (i=0; i<args.length; i++) {
+ j = args[i].indexOf('=');
+ if (j) args[i] = args[i].substring(0,j);
+ }
+ var additions = "";
+ for (i=0; i<page_args.length; i++) {
+ var exists = false;
+ for (j=0; j<args.length; j++)
+ if (args[j] == page_args[i][0]) { exists = true; break; }
+ if (!exists) str += "&" + page_args[i][0] + "=" + page_args[i][1];
+ }
+ a.href = prefix + "?" + str + suffix;
+ }
+}
+
+// Cookies --------------------------------------------------------------------
+
+function GetCookie(key, def) {
+ var i, cookiestrs;
+ try {
+ if (document.cookie.length <= 0) return def;
+ cookiestrs = document.cookie.split(/; */);
+ } catch (e) { return def; }
+ for (i = 0; i < cookiestrs.length; i++) {
+ var cur = cookiestrs[i];
+ var eql = cur.indexOf('=');
+ if (eql >= 0 && cur.substring(0,eql) == key)
+ return unescape(cur.substring(eql+1));
+ }
+ return def;
+}
+
+function SetCookie(key, val) {
+ var d = new Date();
+ d.setTime(d.getTime()+(365*24*60*60*1000));
+ try {
+ document.cookie =
+ key + "=" + escape(val) + "; expires="+ d.toGMTString() + "; path=/";
+ } catch (e) {}
+}
+
+// note that this always stores a directory name, ending with a "/"
+function SetPLTRoot(ver, relative) {
+ var root = location.protocol + "//" + location.host
+ + NormalizePath(location.pathname.replace(/[^\/]*$/, relative));
+ SetCookie("PLT_Root."+ver, root);
+}
+
+// adding index.html works because of the above
+function GotoPLTRoot(ver, relative) {
+ var u = GetCookie("PLT_Root."+ver, null);
+ if (u == null) return true; // no cookie: use plain up link
+ // the relative path is optional, default goes to the toplevel start page
+ if (!relative) relative = "index.html";
+ location = u + relative;
+ return false;
+}
+
+// Utilities ------------------------------------------------------------------
+
+normalize_rxs = [/\/\/+/g, /\/\.(\/|$)/, /\/[^\/]*\/\.\.(\/|$)/];
+function NormalizePath(path) {
+ var tmp, i;
+ for (i = 0; i < normalize_rxs.length; i++)
+ while ((tmp = path.replace(normalize_rxs[i], "/")) != path) path = tmp;
+ return path;
+}
+
+// `noscript' is problematic in some browsers (always renders as a
+// block), use this hack instead (does not always work!)
+// document.write("<style>mynoscript { display:none; }</style>");
+
+// Interactions ---------------------------------------------------------------
+
+function DoSearchKey(event, field, ver, top_path) {
+ var val = field.value;
+ if (event && event.keyCode == 13) {
+ var u = GetCookie("PLT_Root."+ver, null);
+ if (u == null) u = top_path; // default: go to the top path
+ u += "search/index.html?q=" + escape(val);
+ if (page_query_string) u += "&" + page_query_string;
+ location = u;
+ return false;
+ }
+ return true;
+}
+
+function TocviewToggle(glyph, id) {
+ var s = document.getElementById(id).style;
+ var expand = s.display == "none";
+ s.display = expand ? "block" : "none";
+ glyph.innerHTML = expand ? "▼" : "►";
+}
+
+// Page Init ------------------------------------------------------------------
+
+// Note: could make a function that inspects and uses window.onload to chain to
+// a previous one, but this file needs to be required first anyway, since it
+// contains utilities for all other files.
+var on_load_funcs = [];
+function AddOnLoad(fun) { on_load_funcs.push(fun); }
+window.onload = function() {
+ for (var i=0; i<on_load_funcs.length; i++) on_load_funcs[i]();
+};
+
+AddOnLoad(function(){
+ var links = document.getElementsByTagName("a");
+ for (var i=0; i<links.length; i++) MergePageArgsIntoLink(links[i]);
+ var label = GetPageArg("ctxtname",false);
+ if (!label) return;
+ var indicator = document.getElementById("contextindicator");
+ if (!indicator) return;
+ indicator.innerHTML = label;
+ indicator.style.display = "block";
+ });
diff --git a/scribble-style.css b/scribble-style.css
diff --git a/scribble.css b/scribble.css
@@ -0,0 +1,471 @@
+
+/* CSS seems backward: List all the classes for which we want a
+ particular font, so that the font can be changed in one place. (It
+ would be nicer to reference a font definition from all the places
+ that we want it.)
+
+ As you read the rest of the file, remember to double-check here to
+ see if any font is set. */
+
+/* Monospace: */
+.maincolumn, .refpara, .refelem, .tocset, .stt, .hspace, .refparaleft, .refelemleft {
+ font-family: monospace;
+}
+
+/* Serif: */
+.main, .refcontent, .tocview, .tocsub, i {
+ font-family: serif;
+}
+
+/* Sans-serif: */
+.version, .versionNoNav {
+ font-family: sans-serif;
+}
+
+/* ---------------------------------------- */
+
+p, .SIntrapara {
+ display: block;
+ margin: 1em 0;
+}
+
+h2 { /* per-page main title */
+ margin-top: 0;
+}
+
+h3, h4, h5, h6, h7, h8 {
+ margin-top: 1.75em;
+ margin-bottom: 0.5em;
+}
+
+.SSubSubSubSection {
+ font-weight: bold;
+ font-size: 0.83em; /* should match h5; from HTML 4 reference */
+}
+
+/* Needed for browsers like Opera, and eventually for HTML 4 conformance.
+ This means that multiple paragraphs in a table element do not have a space
+ between them. */
+table p {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+/* ---------------------------------------- */
+/* Main */
+
+body {
+ color: black;
+ background-color: #ffffff;
+}
+
+table td {
+ padding-left: 0;
+ padding-right: 0;
+}
+
+.maincolumn {
+ width: 43em;
+ margin-right: -40em;
+ margin-left: 15em;
+}
+
+.main {
+ text-align: left;
+}
+
+/* ---------------------------------------- */
+/* Navigation */
+
+.navsettop, .navsetbottom {
+ background-color: #f0f0e0;
+ padding: 0.25em 0 0.25em 0;
+}
+
+.navsettop {
+ margin-bottom: 1.5em;
+ border-bottom: 2px solid #e0e0c0;
+}
+
+.navsetbottom {
+ margin-top: 2em;
+ border-top: 2px solid #e0e0c0;
+}
+
+.navleft {
+ margin-left: 1ex;
+ position: relative;
+ float: left;
+ white-space: nowrap;
+}
+.navright {
+ margin-right: 1ex;
+ position: relative;
+ float: right;
+ white-space: nowrap;
+}
+.nonavigation {
+ color: #e0e0e0;
+}
+
+.searchform {
+ display: inline;
+ margin: 0;
+ padding: 0;
+}
+
+.searchbox {
+ width: 16em;
+ margin: 0px;
+ padding: 0px;
+ background-color: #eee;
+ border: 1px solid #ddd;
+ text-align: center;
+ vertical-align: middle;
+}
+
+#contextindicator {
+ position: fixed;
+ background-color: #c6f;
+ color: #000;
+ font-family: monospace;
+ font-weight: bold;
+ padding: 2px 10px;
+ display: none;
+ right: 0;
+ bottom: 0;
+}
+
+/* ---------------------------------------- */
+/* Version */
+
+.versionbox {
+ position: relative;
+ float: right;
+ left: 2em;
+ height: 0em;
+ width: 13em;
+ margin: 0em -13em 0em 0em;
+}
+.version {
+ font-size: small;
+}
+.versionNoNav {
+ font-size: xx-small; /* avoid overlap with author */
+}
+
+/* ---------------------------------------- */
+/* Margin notes */
+
+.refpara, .refelem {
+ position: relative;
+ float: right;
+ left: 2em;
+ height: 0em;
+ width: 13em;
+ margin: 0em -13em 0em 0em;
+}
+
+.refpara, .refparaleft {
+ top: -1em;
+}
+
+.refcolumn {
+ background-color: #F5F5DC;
+ display: block;
+ position: relative;
+ width: 13em;
+ font-size: 85%;
+ border: 0.5em solid #F5F5DC;
+ margin: 0 0 0 0;
+}
+
+.refcontent {
+ margin: 0 0 0 0;
+}
+
+.refcontent p {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.refparaleft {
+ position: relative;
+ float: left;
+ right: 2em;
+ height: 0em;
+ width: 13em;
+ margin: 0em 0em 0em -13em;
+}
+
+.refcolumnleft, .refelemleft {
+ background-color: #F5F5DC;
+ display: block;
+ position: relative;
+ width: 13em;
+ font-size: 85%;
+ border: 0.5em solid #F5F5DC;
+ margin: 0 0 0 0;
+}
+
+
+/* ---------------------------------------- */
+/* Table of contents, inline */
+
+.toclink {
+ text-decoration: none;
+ color: blue;
+ font-size: 85%;
+}
+
+.toptoclink {
+ text-decoration: none;
+ color: blue;
+ font-weight: bold;
+}
+
+/* ---------------------------------------- */
+/* Table of contents, left margin */
+
+.tocset {
+ position: relative;
+ float: left;
+ width: 12.5em;
+ margin-right: 2em;
+}
+.tocset td {
+ vertical-align: text-top;
+}
+
+.tocview {
+ text-align: left;
+ background-color: #f0f0e0;
+}
+
+.tocsub {
+ text-align: left;
+ margin-top: 0.5em;
+ background-color: #f0f0e0;
+}
+
+.tocviewlist, .tocsublist {
+ margin-left: 0.2em;
+ margin-right: 0.2em;
+ padding-top: 0.2em;
+ padding-bottom: 0.2em;
+}
+.tocviewlist table {
+ font-size: 82%;
+}
+
+.tocviewsublist, .tocviewsublistonly, .tocviewsublisttop, .tocviewsublistbottom {
+ margin-left: 0.4em;
+ border-left: 1px solid #bbf;
+ padding-left: 0.8em;
+}
+.tocviewsublist {
+ margin-bottom: 1em;
+}
+.tocviewsublist table,
+.tocviewsublistonly table,
+.tocviewsublisttop table,
+.tocviewsublistbottom table {
+ font-size: 75%;
+}
+
+.tocviewtitle * {
+ font-weight: bold;
+}
+
+.tocviewlink {
+ text-decoration: none;
+ color: blue;
+}
+
+.tocviewselflink {
+ text-decoration: underline;
+ color: blue;
+}
+
+.tocviewtoggle {
+ text-decoration: none;
+ color: blue;
+ font-size: 75%; /* looks better, and avoids bounce when toggling sub-sections due to font alignments */
+}
+
+.tocsublist td {
+ padding-left: 1em;
+ text-indent: -1em;
+}
+
+.tocsublinknumber {
+ font-size: 82%;
+}
+
+.tocsublink {
+ font-size: 82%;
+ text-decoration: none;
+}
+
+.tocsubseclink {
+ font-size: 82%;
+ text-decoration: none;
+}
+
+.tocsubnonseclink {
+ font-size: 82%;
+ text-decoration: none;
+ padding-left: 0.5em;
+}
+
+.tocsubtitle {
+ font-size: 82%;
+ font-style: italic;
+ margin: 0.2em;
+}
+
+.sepspace {
+ font-size: 40%;
+}
+
+.septitle {
+ font-size: 70%;
+}
+
+/* ---------------------------------------- */
+/* Some inline styles */
+
+.indexlink {
+ text-decoration: none;
+}
+
+.nobreak {
+ white-space: nowrap;
+}
+
+.stt {
+}
+
+.title {
+ font-size: 200%;
+ font-weight: normal;
+ margin-top: 2.8em;
+ text-align: center;
+}
+
+pre { margin-left: 2em; }
+blockquote { margin-left: 2em; }
+
+ol { list-style-type: decimal; }
+ol ol { list-style-type: lower-alpha; }
+ol ol ol { list-style-type: lower-roman; }
+ol ol ol ol { list-style-type: upper-alpha; }
+
+i {
+}
+
+.SCodeFlow {
+ display: block;
+ margin-left: 1em;
+ margin-bottom: 0em;
+ margin-right: 1em;
+ margin-top: 0em;
+ white-space: nowrap;
+}
+
+.SVInsetFlow {
+ display: block;
+ margin-left: 0em;
+ margin-bottom: 0em;
+ margin-right: 0em;
+ margin-top: 0em;
+}
+
+.SubFlow {
+ display: block;
+ margin: 0em;
+}
+
+.boxed {
+ width: 100%;
+ background-color: #E8E8FF;
+}
+
+.hspace {
+}
+
+.slant {
+ font-style: oblique;
+}
+
+.badlink {
+ text-decoration: underline;
+ color: red;
+}
+
+.plainlink {
+ text-decoration: none;
+ color: blue;
+}
+
+.techoutside { text-decoration: underline; color: #b0b0b0; }
+.techoutside:hover { text-decoration: underline; color: blue; }
+
+/* .techinside:hover doesn't work with FF, .techinside:hover>
+ .techinside doesn't work with IE, so use both (and IE doesn't
+ work with inherit in the second one, so use blue directly) */
+.techinside { color: black; }
+.techinside:hover { color: blue; }
+.techoutside:hover>.techinside { color: inherit; }
+
+.SCentered {
+ text-align: center;
+}
+
+.imageleft {
+ float: left;
+ margin-right: 0.3em;
+}
+
+.Smaller{
+ font-size: 82%;
+}
+
+.Larger{
+ font-size: 122%;
+}
+
+/* A hack, inserted to break some Scheme ids: */
+.mywbr {
+ width: 0;
+ font-size: 1px;
+}
+
+.compact li p {
+ margin: 0em;
+ padding: 0em;
+}
+
+.noborder img {
+ border: 0;
+}
+
+.SAuthorListBox {
+ position: relative;
+ float: right;
+ left: 2em;
+ top: -2.5em;
+ height: 0em;
+ width: 13em;
+ margin: 0em -13em 0em 0em;
+}
+.SAuthorList {
+ font-size: 82%;
+}
+.SAuthorList:before {
+ content: "by ";
+}
+.author {
+ display: inline;
+ white-space: nowrap;
+}