www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 8a59d450989ec4a57dc4c2c20286a11a7775de47
Author: Greg Hendershott <greghendershott@gmail.com>
Date:   Wed, 24 Oct 2012 15:11:13 -0400

Initial commit.

Diffstat:
Amain.html | 211+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amain.rkt | 818+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aracket.css | 233+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascribble-common.js | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascribble-style.css | 0
Ascribble.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,&quot;tocview_0&quot;);">&#9658;</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&nbsp;</td><td><a href="#(part._.Introduction)" class="tocviewlink" pltdoc="x">Introduction</a></td></tr><tr><td align="right">2&nbsp;</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&nbsp;</td><td><a href="#(part._.Transformers)" class="tocviewlink" pltdoc="x">Transformers</a></td></tr><tr><td align="right">4&nbsp;</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&nbsp;</td><td><a href="#(part._.Syntax_parameters)" class="tocviewlink" pltdoc="x">Syntax parameters</a></td></tr><tr><td align="right">6&nbsp;</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&nbsp;</td><td><a href="#(part._.Other_questions)" class="tocviewlink" pltdoc="x">Other questions</a></td></tr><tr><td align="right">8&nbsp;</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&nbsp;</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>&nbsp;</tt></span><a href="#(part._.Introduction)" class="tocsubseclink" pltdoc="x">Introduction</a></td></tr><tr><td><span class="tocsublinknumber">2<tt>&nbsp;</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>&nbsp;</tt></span><a href="#(part._.Transformers)" class="tocsubseclink" pltdoc="x">Transformers</a></td></tr><tr><td><span class="tocsublinknumber">3.1<tt>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</tt></span><a href="#(part.__.A_pattern_variable_can_t_be_used_outside_of_a_template_)" class="tocsubseclink" pltdoc="x">"A pattern variable can&rsquo;t be used outside of a template"</a></td></tr><tr><td><span class="tocsublinknumber">5<tt>&nbsp;</tt></span><a href="#(part._.Syntax_parameters)" class="tocsubseclink" pltdoc="x">Syntax parameters</a></td></tr><tr><td><span class="tocsublinknumber">6<tt>&nbsp;</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>&nbsp;</tt></span><a href="#(part._.Other_questions)" class="tocsubseclink" pltdoc="x">Other questions</a></td></tr><tr><td><span class="tocsublinknumber">7.1<tt>&nbsp;</tt></span><a href="#(part._.What_s_the_point_of_with-syntax_)" class="tocsubseclink" pltdoc="x">What&rsquo;s the point of <span class="RktSym">with-<wbr></wbr>syntax</span>?</a></td></tr><tr><td><span class="tocsublinknumber">7.2<tt>&nbsp;</tt></span><a href="#(part._.What_s_the_point_of_begin-for-syntax_)" class="tocsubseclink" pltdoc="x">What&rsquo;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>&nbsp;</tt></span><a href="#(part._.What_s_the_point_of_racket_splicing_)" class="tocsubseclink" pltdoc="x">What&rsquo;s the point of <span class="RktSym">racket/<span class="mywbr"> </span>splicing</span>?</a></td></tr><tr><td><span class="tocsublinknumber">8<tt>&nbsp;</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>&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Introduction)" class="toptoclink" pltdoc="x">1<span class="hspace">&nbsp;</span>Introduction</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.The_plan_of_attack)" class="toptoclink" pltdoc="x">2<span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Transformers)" class="toptoclink" pltdoc="x">3<span class="hspace">&nbsp;</span>Transformers</a></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.What_is_a_syntax_transformer_)" class="toclink" pltdoc="x">3.1<span class="hspace">&nbsp;</span>What is a syntax transformer?</a></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.What_is_the_input_)" class="toclink" pltdoc="x">3.2<span class="hspace">&nbsp;</span>What is the input?</a></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Actually_transforming_the_input)" class="toclink" pltdoc="x">3.3<span class="hspace">&nbsp;</span>Actually transforming the input</a></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Compile_time_vs__run_time)" class="toclink" pltdoc="x">3.4<span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Pattern_matching__syntax-case_and_syntax-rules)" class="toptoclink" pltdoc="x">4<span class="hspace">&nbsp;</span>Pattern matching: syntax-case and syntax-rules</a></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Patterns_and_templates)" class="toclink" pltdoc="x">4.1<span class="hspace">&nbsp;</span>Patterns and templates</a></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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">&nbsp;</span>"A pattern variable can&rsquo;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">&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Syntax_parameters)" class="toptoclink" pltdoc="x">5<span class="hspace">&nbsp;</span>Syntax parameters</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Robust_macros__syntax-parse)" class="toptoclink" pltdoc="x">6<span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Other_questions)" class="toptoclink" pltdoc="x">7<span class="hspace">&nbsp;</span>Other questions</a></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.What_s_the_point_of_with-syntax_)" class="toclink" pltdoc="x">7.1<span class="hspace">&nbsp;</span>What&rsquo;s the point of <span class="RktSym">with-syntax</span>?</a></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.What_s_the_point_of_begin-for-syntax_)" class="toclink" pltdoc="x">7.2<span class="hspace">&nbsp;</span>What&rsquo;s the point of <span class="RktSym">begin-for-syntax</span>?</a></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.What_s_the_point_of_racket_splicing_)" class="toclink" pltdoc="x">7.3<span class="hspace">&nbsp;</span>What&rsquo;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">&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.References_.Acknowledgements)" class="toptoclink" pltdoc="x">8<span class="hspace">&nbsp;</span>References/Acknowledgements</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><a href="#(part._.Epilog)" class="toptoclink" pltdoc="x">9<span class="hspace">&nbsp;</span>Epilog</a></p></td></tr></table><h3>1<tt>&nbsp;</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&rsquo;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&rsquo;ll give you the +questions and problems first, so that you can better appreciate and +understand the answers and solutions.</p><h3>2<tt>&nbsp;</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&rsquo;t worry, we&rsquo;ll get to +that soon.</p><p>But if we start there, you&rsquo;re likely to feel overwhelmed by concepts +and terminology, and get very confused. I did.</p><p>1. Instead let&rsquo;s start with the basics: A syntax object and a function +to change it (a "transformer"). We&rsquo;ll work at that level for awhile to +get comfortable and to de-mythologize this whole macro business.</p><p>2. Next, we&rsquo;ll realize that some pattern-matching would make life +easier. We&rsquo;ll learn about <span class="RktSym">syntax-case</span>, and its shorthand +cousin, <span class="RktSym">define-syntax-rule</span>. We&rsquo;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&rsquo;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&rsquo;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&rsquo;t look at them. We also won&rsquo;t spend a lot of time talking +about "hygiene".]</p><p>4. Finally, we&rsquo;ll realize that our macros could be smarter when +they&rsquo;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>&nbsp;</tt><a name="(part._.Transformers)"></a>Transformers</h3><p><table cellspacing="0"><tr><td><p><span class="stt"><span class="hspace">&nbsp;&nbsp;</span><span class="stt">YOU ARE INSIDE A ROOM.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace">&nbsp;&nbsp;</span><span class="stt">THERE ARE KEYS ON THE GROUND.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace">&nbsp;&nbsp;</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">&nbsp;&nbsp;</span><span class="stt"></span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace">&nbsp;&nbsp;</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">&nbsp;&nbsp;</span><span class="stt">HOPELESSLY LOST AND CONFUSED.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace">&nbsp;&nbsp;</span><span class="stt"></span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace">&nbsp;&nbsp;</span><span class="stt">&gt; pick up the keys</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace">&nbsp;&nbsp;</span><span class="stt"></span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace">&nbsp;&nbsp;</span><span class="stt">YOU HAVE A SYNTAX TRANSFORMER</span></span></p></td></tr></table></p><h4>3.1<tt>&nbsp;</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 &#12488;&#12521;&#12531;&#12473;&#12501;&#12457;&#12540;&#12510; +<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&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">foo</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</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">&gt; </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&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">also-foo</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</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">&gt; </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&rsquo;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">&rsquo;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">quoted-foo</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</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">&gt; </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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">say-hi</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace">&nbsp;</span><span class="RktVal">"hi"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">&gt; </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>&nbsp;</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&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">show-me</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">print</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">show-me</span><span class="hspace">&nbsp;</span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">i</span><span class="hspace">&nbsp;</span><span class="RktVal">am</span><span class="hspace">&nbsp;</span><span class="RktVal">a</span><span class="hspace">&nbsp;</span><span class="RktVal">list</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">#&lt;syntax:10:0 (show-me (quote (i am a list)))&gt;</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&#8212;<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&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">if</span><span class="hspace">&nbsp;</span><span class="RktSym">x</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">list</span><span class="hspace">&nbsp;</span><span class="RktVal">"true"</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">syntax-e</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(#&lt;syntax:11:0 if&gt;<span class="stt"> </span>#&lt;syntax:11:0 x&gt;<span class="stt"> </span>#&lt;syntax:11:0 (list "true")&gt;<span class="stt"> </span>#&lt;syntax:11:0 #f&gt;)</span></p></td></tr><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;list</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(#&lt;syntax:11:0 if&gt;<span class="stt"> </span>#&lt;syntax:11:0 x&gt;<span class="stt"> </span>#&lt;syntax:11:0 (list "true")&gt;<span class="stt"> </span>#&lt;syntax:11:0 #f&gt;)</span></p></td></tr><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym">syntax-source</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">syntax-line</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">syntax-column</span><span class="hspace">&nbsp;</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&rsquo;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>&nbsp;</tt><a name="(part._.Actually_transforming_the_input)"></a>Actually transforming the input</h4><p>Let&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">reverse</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">cdr</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="hspace">&nbsp;</span><span class="RktVal">"backwards"</span><span class="hspace">&nbsp;</span><span class="RktVal">"am"</span><span class="hspace">&nbsp;</span><span class="RktVal">"i"</span><span class="hspace">&nbsp;</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&rsquo;s going on here? First we take the input syntax, and give it to +<span class="RktSym">syntax-&gt;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="hspace">&nbsp;</span><span class="RktVal">"backwards"</span><span class="hspace">&nbsp;</span><span class="RktVal">"am"</span><span class="hspace">&nbsp;</span><span class="RktVal">"i"</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">reverse</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">cdr</span><span class="hspace">&nbsp;</span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">"backwards"</span><span class="hspace">&nbsp;</span><span class="RktVal">"am"</span><span class="hspace">&nbsp;</span><span class="RktVal">"i"</span><span class="hspace">&nbsp;</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-&gt;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">values</span><span class="hspace">&nbsp;</span><span class="RktVal">"i"</span><span class="hspace">&nbsp;</span><span class="RktVal">"am"</span><span class="hspace">&nbsp;</span><span class="RktVal">"backwards"</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#&lt;syntax (values "i" "am" "backwards")&gt;</span></p></td></tr></table></blockquote><p>That&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">values</span><span class="hspace">&nbsp;</span><span class="RktVal">"i"</span><span class="hspace">&nbsp;</span><span class="RktVal">"am"</span><span class="hspace">&nbsp;</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>&nbsp;</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&rsquo;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">&lt;condition&gt;</span><span class="stt"> </span><span class="RktSym">&lt;true-expression&gt;</span><span class="stt"> </span><span class="RktSym">&lt;false-expression&gt;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace">&nbsp;</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="hspace">&nbsp;</span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">cond</span><span class="hspace">&nbsp;</span><span class="RktPn">[</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktSym">else</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktVal">"true"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace">&nbsp;</span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace">&nbsp;</span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace">&nbsp;</span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace">&nbsp;</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&rsquo;t always +practical.</p></blockquote></blockquote></blockquote><p>Oops. Because the expressions have a side-effect, it&rsquo;s obvious that +they are both evaluated. And that could be a problem&#8212;<wbr></wbr>what if the +side-effect includes deleting a file on disk? You wouldn&rsquo;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&rsquo;t work as a plain function. However a syntax +transformer can rearrange the syntax &ndash; rewrite the code &ndash; at compile +time. The pieces of syntax are moved around, but they aren&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktSym">xs</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;list</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace">&nbsp;</span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadr</span><span class="hspace">&nbsp;</span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">caddr</span><span class="hspace">&nbsp;</span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace">&nbsp;</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadddr</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace">&nbsp;</span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace">&nbsp;</span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace">&nbsp;</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&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="hspace">&nbsp;</span><span class="RktVal">"true"</span><span class="hspace">&nbsp;</span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">#&lt;syntax:31:0 (our-if-v2 #t "true" "false")&gt;</span></p></td></tr></table></blockquote><p>1. We take the original syntax, and use <span class="RktSym">syntax-&gt;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktSym">xs</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace">&nbsp;</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&#8212;<wbr></wbr>the condition, true-expression, and +false-expression&#8212;<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">&nbsp;</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">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">[</span><span class="RktSym">else</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;</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-&gt;syntax</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace">&nbsp;</span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadr</span><span class="hspace">&nbsp;</span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">caddr</span><span class="hspace">&nbsp;</span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace">&nbsp;</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadddr</span><span class="hspace">&nbsp;</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">#&lt;syntax (cond (#t "true") (else "fals...&gt;</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&rsquo;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&rsquo;t care about the first item in the +syntax list. We didn&rsquo;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&rsquo;t use <span class="RktSym">name</span> when we used pattern-matching. In general, a +syntax transformer won&rsquo;t care about that, because it is the name of +the transformer binding. In other words, a macro usually doesn&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktSym">xs</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;list</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace">&nbsp;</span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadr</span><span class="hspace">&nbsp;</span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">caddr</span><span class="hspace">&nbsp;</span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace">&nbsp;</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym">cadddr</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">our-if-using-match</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">match</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;list</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">list</span><span class="hspace">&nbsp;</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="hspace">&nbsp;</span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace">&nbsp;</span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="hspace">&nbsp;</span><span class="RktVal">"true"</span><span class="hspace">&nbsp;</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">&nbsp;</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">&nbsp;&nbsp;</span><span class="RktErr">in module: 'program</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktErr">phase: 1</span></p></td></tr></table></blockquote><p>But wait, we can&rsquo;t. It&rsquo;s complaining that <span class="RktSym">match</span> isn&rsquo;t +defined. We havne&rsquo;t required the <span class="RktSym">racket/match</span> module?</p><p>It turns out we haven&rsquo;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&#8212;<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>&#8212;<wbr></wbr>the <span class="RktSym">for-syntax</span> +part meaning, "for compile time".</p><p>So let&rsquo;s try that:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym">require</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">for-syntax</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">our-if-using-match-v2</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">match</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;list</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">list</span><span class="hspace">&nbsp;</span><span class="RktSym">_</span><span class="hspace">&nbsp;</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="hspace">&nbsp;</span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace">&nbsp;</span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match-v2</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="hspace">&nbsp;</span><span class="RktVal">"true"</span><span class="hspace">&nbsp;</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&rsquo;t work properly +as run time functions.</p><p>Some other good news is that there isn&rsquo;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&rsquo;re not working at run +time. Sometimes that&rsquo;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>&nbsp;</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&rsquo;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&rsquo;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">&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">for-syntax</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;</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">&nbsp;</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">&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">match</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;list</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;</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">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">_</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">condition</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">true-expr</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">stx</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;</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">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">[</span><span class="RktSym">else</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-case</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace">&nbsp;</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="hspace">&nbsp;</span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">cond</span><span class="hspace">&nbsp;</span><span class="RktPn">[</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktSym">else</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-case</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="hspace">&nbsp;</span><span class="RktVal">"true"</span><span class="hspace">&nbsp;</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&#8212;<wbr></wbr>where we specify the new syntax&#8212;<wbr></wbr>is +simpler. We don&rsquo;t need to do quasiquoting and unquoting. We don&rsquo;t need +to use <span class="RktSym">datum-&gt;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&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax-rule</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-rule</span><span class="hspace">&nbsp;</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="hspace">&nbsp;</span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">cond</span><span class="hspace">&nbsp;</span><span class="RktPn">[</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktSym">else</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-rule</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="hspace">&nbsp;</span><span class="RktVal">"true"</span><span class="hspace">&nbsp;</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&rsquo;s the thing about <span class="RktSym">define-syntax-rule</span>. Because it&rsquo;s so +simple, <span class="RktSym">define-syntax-rule</span> is ofen the first thing people are +taught about macros. But it&rsquo;s almost deceptively simple. It looks so +much like defining a normal run time function&#8212;<wbr></wbr>yet it&rsquo;s not. It&rsquo;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&rsquo;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&rsquo;s +shorthand.</p><h4>4.1<tt>&nbsp;</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&rsquo;m +not going to regurgitate that here.</p><p>Instead, let&rsquo;s look at some ways we&rsquo;re likely to get tripped up.</p><h5>4.1.1<tt>&nbsp;</tt><a name="(part.__.A_pattern_variable_can_t_be_used_outside_of_a_template_)"></a>"A pattern variable can&rsquo;t be used outside of a template"</h5><p>Let&rsquo;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&#8212;<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&rsquo;s pretend we&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace">&nbsp;</span><span class="RktSym">a</span><span class="hspace">&nbsp;</span><span class="RktSym">b</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">let</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">string-&gt;symbol</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace">&nbsp;</span><span class="RktVal">"~a-~a"</span><span class="hspace">&nbsp;</span><span class="RktSym">a</span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;</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&rsquo;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&rsquo;t part of that template. It +sounds like we can&rsquo;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&#8212;<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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace">&nbsp;</span><span class="RktSym">a</span><span class="hspace">&nbsp;</span><span class="RktSym">b</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">string-&gt;symbol</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace">&nbsp;</span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</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">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;</span><span class="RktErr">in: a</span></p></td></tr></table></blockquote><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>I don&rsquo;t have a clear explanation for <span style="font-style: italic">why</span> they +need to be <span class="stt">#</span><span class="stt">&rsquo;</span><span class="stt">a</span> and <span class="stt">#</span><span class="stt">&rsquo;</span><span class="stt">b</span>. Can anyone help?</p></blockquote></blockquote></blockquote><p>Well, not quite. We can&rsquo;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">&rsquo;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok1</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace">&nbsp;</span><span class="RktSym">a</span><span class="hspace">&nbsp;</span><span class="RktSym">b</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">string-&gt;symbol</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace">&nbsp;</span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</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">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok1</span><span class="hspace">&nbsp;</span><span class="RktSym">first</span><span class="hspace">&nbsp;</span><span class="RktSym">second</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">&gt; </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&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok2</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace">&nbsp;</span><span class="RktSym">a</span><span class="hspace">&nbsp;</span><span class="RktSym">b</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">with-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">datum-&gt;syntax</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">string-&gt;symbol</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace">&nbsp;</span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktRdr">#`</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok2</span><span class="hspace">&nbsp;</span><span class="RktSym">foo</span><span class="hspace">&nbsp;</span><span class="RktSym">bar</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">&gt; </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&rsquo;t need the +<span class="RktSym">datum-&gt;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok3</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-case</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">_</span><span class="hspace">&nbsp;</span><span class="RktSym">a</span><span class="hspace">&nbsp;</span><span class="RktSym">b</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">with-syntax</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">string-&gt;symbol</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">format</span><span class="hspace">&nbsp;</span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-&gt;datum</span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktRdr">#`</span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace">&nbsp;</span><span class="RktSym">args</span><span class="hspace">&nbsp;</span><span class="RktSym">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktSym">body0</span><span class="hspace">&nbsp;</span><span class="RktSym">body</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok3</span><span class="hspace">&nbsp;</span><span class="RktSym">foo</span><span class="hspace">&nbsp;</span><span class="RktSym">bar</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">&gt; </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">&rsquo;</span><span class="stt"></span> on the pattern variables.</p><h3>5<tt>&nbsp;</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">&nbsp;</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">&nbsp;</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">&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">if</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax-rule</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace">&nbsp;</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="hspace">&nbsp;</span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">let</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">it</span><span class="hspace">&nbsp;</span><span class="RktSym">condition</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">if</span><span class="hspace">&nbsp;</span><span class="RktSym">it</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktSym">true-expr</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace">&nbsp;</span><span class="RktVal">#t</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace">&nbsp;</span><span class="RktSym">it</span><span class="RktPn">)</span><span class="hspace">&nbsp;</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">&nbsp;</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">&nbsp;&nbsp;</span><span class="RktErr">in module: 'program</span></p></td></tr></table></blockquote><p>Wait, what&#8212;<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&rsquo;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&rsquo;re probably familiar with regular +parameters in Racket.</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktSym">current-foo</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">make-parameter</span><span class="hspace">&nbsp;</span><span class="RktVal">"some default value"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">&gt; </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">&gt; </span><span class="RktPn">(</span><span class="RktSym">parameterize</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">current-foo</span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</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">&gt; </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&rsquo;re the target +audience I&rsquo;m writing for, you don&rsquo;t know them yet. You can skip +learning them now. (Someday if you want to understand someone else&rsquo;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&rsquo;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">&gt; </span><span class="RktPn">(</span><span class="RktSym">require</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax-parameter</span><span class="hspace">&nbsp;</span><span class="RktSym">it</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">raise-syntax-error</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-e</span><span class="hspace">&nbsp;</span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define-syntax-rule</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace">&nbsp;</span><span class="RktSym">condition</span><span class="hspace">&nbsp;</span><span class="RktSym">true-expr</span><span class="hspace">&nbsp;</span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">let</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">tmp</span><span class="hspace">&nbsp;</span><span class="RktSym">condition</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">if</span><span class="hspace">&nbsp;</span><span class="RktSym">tmp</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">syntax-parameterize</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">it</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">make-rename-transformer</span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktSym">true-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace">&nbsp;&nbsp;</span></span><span class="hspace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace">&nbsp;</span><span class="RktVal">10</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace">&nbsp;</span><span class="RktSym">it</span><span class="RktPn">)</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace">&nbsp;</span><span class="RktSym">it</span><span class="RktPn">)</span><span class="hspace">&nbsp;</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">&gt; </span><span class="RktPn">(</span><span class="RktSym">define</span><span class="hspace">&nbsp;</span><span class="RktSym">it</span><span class="hspace">&nbsp;</span><span class="RktVal">10</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">&gt; </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&rsquo;t otherwise defined, we get an error like we want:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">&gt; </span><span class="RktPn">(</span><span class="RktSym">displayln</span><span class="hspace">&nbsp;</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>&nbsp;</tt><a name="(part._.Robust_macros__syntax-parse)"></a>Robust macros: syntax-parse</h3><p>TO-DO.</p><h3>7<tt>&nbsp;</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>&nbsp;</tt><a name="(part._.What_s_the_point_of_with-syntax_)"></a>What&rsquo;s the point of <span class="RktSym">with-syntax</span>?</h4><p>Done.</p><h4>7.2<tt>&nbsp;</tt><a name="(part._.What_s_the_point_of_begin-for-syntax_)"></a>What&rsquo;s the point of <span class="RktSym">begin-for-syntax</span>?</h4><p>TO-DO.</p><h4>7.3<tt>&nbsp;</tt><a name="(part._.What_s_the_point_of_racket_splicing_)"></a>What&rsquo;s the point of <span class="RktSym">racket/splicing</span>?</h4><p>TO-DO.</p><h3>8<tt>&nbsp;</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 +&#8216;syntax-case&#8217; Macros</a>, which explains many key details. However it&rsquo;s written +especially for people already familiar with "un-hygienic" "defmacro" +style macros. If you&rsquo;re not familiar with those, it may seem slightly +weird to the extent it&rsquo;s trying to convince you to change an opinion +you don&rsquo;t have. Even so, many key details are presented in Eli&rsquo;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>&nbsp;</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&rsquo;s just that I see mountains once again +as mountains, and rivers once again as rivers"</p><p><span class="Smaller">&ndash;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">&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">and</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">mountains</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">rivers</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">not</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">and</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">mountains</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">rivers</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">lambda</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">and</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">mountains</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">eq?</span><span class="RktMeta"></span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><span class="RktSym">'</span><span class="RktSym">rivers</span><span class="RktMeta"></span><span class="hspace">&nbsp;</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">&nbsp;</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 ? "&#9660;" : "&#9658;"; +} + +// 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; +}