104 lines
89 KiB
HTML
104 lines
89 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><title>3 Transform!</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="manual-style.css" title="default"/><link rel="stylesheet" type="text/css" href="manual-racket.css" title="default"/><link rel="stylesheet" type="text/css" href="gh.css" title="default"/><script type="text/javascript" src="scribble-common.js"></script><script type="text/javascript" src="manual-racket.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--><meta name="keywords" content="Racket,macros,Scheme"><meta name="description" content="Practical Racket macros"><meta name="author" content="Greg Hendershott"><meta name="charset" content="utf-8"><link href='http://fonts.googleapis.com/css?family=Fenix' rel='stylesheet' type='text/css'><script type="text/javascript">var _gaq = _gaq || [];_gaq.push(['_setAccount', 'UA-29709446-1']);_gaq.push(['_setDomainName', 'greghendershott.com']);_gaq.push(['_trackPageview']);(function() {var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);})();</script></head><body id="scribble-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist tocviewlisttopspace"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">Fear of Macros</a></td></tr></table></div><div class="tocviewsublisttop" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="Preface.html" class="tocviewlink" data-pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" data-pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="" class="tocviewselflink" data-pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" data-pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="Syntax_parameters.html" class="tocviewlink" data-pltdoc="x">Syntax parameters</a></td></tr><tr><td align="right">6 </td><td><a href="What_s_the_point_of_splicing-let_.html" class="tocviewlink" data-pltdoc="x">What’s the point of <span class="RktSym"><span class="RktStxLink">splicing-<wbr></wbr>let</span></span>?</a></td></tr><tr><td align="right">7 </td><td><a href="Robust_macros__syntax-parse.html" class="tocviewlink" data-pltdoc="x">Robust macros:<span class="mywbr"> </span> syntax-<wbr></wbr>parse</a></td></tr><tr><td align="right">8 </td><td><a href="References_and_Acknowledgments.html" class="tocviewlink" data-pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" data-pltdoc="x">Epilogue</a></td></tr></table></div></div><div class="tocviewlist"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_1");">►</a></td><td>3 </td><td><a href="" class="tocviewselflink" data-pltdoc="x">Transform!</a></td></tr></table><div class="tocviewsublistbottom" style="display: none;" id="tocview_1"><table cellspacing="0" cellpadding="0"><tr><td align="right">3.1 </td><td><a href="#%28part._.What_is_a_syntax_transformer_%29" class="tocviewlink" data-pltdoc="x">What is a syntax transformer?</a></td></tr><tr><td align="right">3.2 </td><td><a href="#%28part._.What_s_the_input_%29" class="tocviewlink" data-pltdoc="x">What’s the input?</a></td></tr><tr><td align="right">3.3 </td><td><a href="#%28part._.Actually_transforming_the_input%29" class="tocviewlink" data-pltdoc="x">Actually transforming the input</a></td></tr><tr><td align="right">3.4 </td><td><a href="#%28part._.Compile_time_vs__run_time%29" class="tocviewlink" data-pltdoc="x">Compile time vs. run time</a></td></tr><tr><td align="right">3.5 </td><td><a href="#%28part._begin-for-syntax%29" class="tocviewlink" data-pltdoc="x"><span class="RktSym"><span class="RktStxLink">begin-<wbr></wbr>for-<wbr></wbr>syntax</span></span></a></td></tr></table></div></div></div><div class="tocsub"><div class="tocsubtitle">On this page:</div><table class="tocsublist" cellspacing="0"><tr><td><span class="tocsublinknumber">3.1<tt> </tt></span><a href="#%28part._.What_is_a_syntax_transformer_%29" class="tocsubseclink" data-pltdoc="x">What is a syntax transformer?</a></td></tr><tr><td><span class="tocsublinknumber">3.2<tt> </tt></span><a href="#%28part._.What_s_the_input_%29" class="tocsubseclink" data-pltdoc="x">What’s the input?</a></td></tr><tr><td><span class="tocsublinknumber">3.3<tt> </tt></span><a href="#%28part._.Actually_transforming_the_input%29" class="tocsubseclink" data-pltdoc="x">Actually transforming the input</a></td></tr><tr><td><span class="tocsublinknumber">3.4<tt> </tt></span><a href="#%28part._.Compile_time_vs__run_time%29" class="tocsubseclink" data-pltdoc="x">Compile time vs. run time</a></td></tr><tr><td><span class="tocsublinknumber">3.5<tt> </tt></span><a href="#%28part._begin-for-syntax%29" class="tocsubseclink" data-pltdoc="x"><span class="RktSym"><span class="RktStxLink">begin-<wbr></wbr>for-<wbr></wbr>syntax</span></span></a></td></tr></table></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"><div class="nosearchform"></div> </span><span class="navright"> <a href="Our_plan_of_attack.html" title="backward to "2 Our plan of attack"" data-pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" data-pltdoc="x">up</a> <a href="pattern-matching.html" title="forward to "4 Pattern matching: syntax-case and syntax-rules"" data-pltdoc="x">next →</a></span> </div><h3>3<tt> </tt><a name="(part._.Transform_)"></a>Transform!</h3><p><table cellspacing="0" cellpadding="0"><tr><td><p><span class="hspace"> </span><span class="stt">YOU ARE INSIDE A ROOM.</span></p></td></tr><tr><td><p><span class="hspace"> </span><span class="stt">THERE ARE KEYS ON THE GROUND.</span></p></td></tr><tr><td><p><span class="hspace"> </span><span class="stt">THERE IS A SHINY BRASS LAMP NEARBY.</span></p></td></tr><tr><td><p><span class="hspace"> </span><span class="stt"></span></p></td></tr><tr><td><p><span class="hspace"> </span><span class="stt">IF YOU GO THE WRONG WAY, YOU WILL BECOME</span></p></td></tr><tr><td><p><span class="hspace"> </span><span class="stt">HOPELESSLY LOST AND CONFUSED.</span></p></td></tr><tr><td><p><span class="hspace"> </span><span class="stt"></span></p></td></tr><tr><td><p><span class="hspace"> </span><span class="stt">> pick up the keys</span></p></td></tr><tr><td><p><span class="hspace"> </span><span class="stt"></span></p></td></tr><tr><td><p><span class="hspace"> </span><span class="stt">YOU HAVE A SYNTAX TRANSFORMER</span></p></td></tr></table></p><h4>3.1<tt> </tt><a name="(part._.What_is_a_syntax_transformer_)"></a>What is a syntax transformer?</h4><p>A syntax transformer is not one of the トランスフォーマ
|
|
<a href="http://en.wikipedia.org/wiki/Transformers">transformers</a>.</p><p>Instead, it is simply a function. The function takes syntax and
|
|
returns syntax. It transforms syntax.</p><p>Here’s a transformer function that ignores its input syntax, and
|
|
always outputs syntax for a string literal:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">foo</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._syntax%29%29" class="RktStxLink" data-pltdoc="x">syntax</a></span><span class="hspace"> </span><span class="RktVal">"I am foo"</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr></table></blockquote><p>Using it:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"I am foo"</span></p></td></tr></table></blockquote><p>When we use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span>, we’re making a transformer
|
|
<span style="font-style: italic">binding</span>. This tells the Racket compiler, "Whenever you
|
|
encounter a chunk of syntax starting with <span class="RktSym">foo</span>, please give it
|
|
to my transformer function, and replace it with the syntax I give back
|
|
to you." So Racket will give anything that looks like <span class="RktPn">(</span><span class="RktSym">foo</span><span class="stt"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._......%29%29" class="RktStxLink" data-pltdoc="x">...</a></span><span class="RktPn">)</span> to our function, and we can return new syntax to use
|
|
instead. Much like a search-and-replace.</p><p>Maybe you know that the usual way to define a function in Racket:</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">f</span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._......%29%29" class="RktStxLink" data-pltdoc="x">...</a></span><span class="RktPn">)</span></p></blockquote><p>is shorthand for:</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">f</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">x</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._......%29%29" class="RktStxLink" data-pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span></p></blockquote><p>That shorthand lets you avoid typing <span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span> and some parentheses.</p><p>Well there is a similar shorthand for <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">also-foo</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._syntax%29%29" class="RktStxLink" data-pltdoc="x">syntax</a></span><span class="hspace"> </span><span class="RktVal">"I am also foo"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">also-foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"I am also foo"</span></p></td></tr></table></blockquote><p>What we want to remember is that this is simply shorthand. We are
|
|
still defining a transformer function, which takes syntax and returns
|
|
syntax. Everything we do with macros, will be built on top of this
|
|
basic idea. It’s not magic.</p><p>Speaking of shorthand, there is also a shorthand for <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._syntax%29%29" class="RktStxLink" data-pltdoc="x">syntax</a></span>,
|
|
which is <span class="stt">#</span><span class="stt">’</span><span class="stt"></span>:</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p><span class="stt">#</span><span class="stt">’</span><span class="stt"></span> is short for <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._syntax%29%29" class="RktStxLink" data-pltdoc="x">syntax</a></span> much like
|
|
<span class="stt"></span><span class="stt">’</span><span class="stt"></span> is short for <span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#%28form._%28%28quote._~23~25kernel%29._quote%29%29" class="RktStxLink" data-pltdoc="x">quote</a></span>.</p></blockquote></blockquote></blockquote><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">quoted-foo</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktVal">"I am also foo, using #' instead of syntax"</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">quoted-foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"I am also foo, using #' instead of syntax"</span></p></td></tr></table></blockquote><p>We’ll use the <span class="stt">#</span><span class="stt">’</span><span class="stt"></span> shorthand from now on.</p><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"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28lib._racket%2Fprivate%2Fmisc..rkt%29._displayln%29%29" class="RktValLink" data-pltdoc="x">displayln</a></span><span class="stt"> </span><span class="RktVal">"hi"</span><span class="RktPn">)</span>?</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">say-hi</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28lib._racket%2Fprivate%2Fmisc..rkt%29._displayln%29%29" class="RktValLink" data-pltdoc="x">displayln</a></span><span class="hspace"> </span><span class="RktVal">"hi"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">say-hi</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">hi</span></p></td></tr></table></blockquote><p>When Racket expands our program, it sees the occurrence of
|
|
<span class="RktPn">(</span><span class="RktSym">say-hi</span><span class="RktPn">)</span>, and sees it has a transformer function for that. It
|
|
calls our function with the old syntax, and we return the new syntax,
|
|
which is used to evaluate and run our program.</p><h4>3.2<tt> </tt><a name="(part._.What_s_the_input_)"></a>What’s the input?</h4><p>Our examples so far have ignored the input syntax and output some
|
|
fixed syntax. But typically we will want to transform the input syntax
|
|
into something else.</p><p>Let’s start by looking closely at what the input actually <span style="font-style: italic">is</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">show-me</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28quote._~23~25kernel%29._print%29%29" class="RktValLink" data-pltdoc="x">print</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">show-me</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">+</span><span class="hspace"> </span><span class="RktVal">1</span><span class="hspace"> </span><span class="RktVal">2</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">#<syntax:10:0 (show-me (quote (+ 1 2)))></span></p></td></tr></table></blockquote><p>The <span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28quote._~23~25kernel%29._print%29%29" class="RktValLink" data-pltdoc="x">print</a></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">+</span><span class="stt"> </span><span class="RktVal">1</span><span class="stt"> </span><span class="RktVal">2</span><span class="RktVal">)</span>.</p><p>Racket syntax is also decorated with some interesting information such
|
|
as the source file, line number, and column. Finally, it has
|
|
information about lexical scoping (which you don’t need to worry about
|
|
now, but will turn out to be important later.)</p><p>There are a variety of functions available to access a syntax object.
|
|
Let’s define a piece of syntax:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28quote._~23~25kernel%29._if%29%29" class="RktStxLink" data-pltdoc="x">if</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._list%29%29" class="RktValLink" data-pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#f</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktSym">stx</span></td></tr><tr><td><p><span class="RktRes">#<syntax:11:0 (if x (list "true") #f)></span></p></td></tr></table></blockquote><p>Now let’s use functions that access the syntax object. The source
|
|
information functions are:</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-source%29%29" class="RktValLink" data-pltdoc="x">syntax-source</a></span><span class="stt"> </span><span class="RktSym">stx</span><span class="RktPn">)</span> is returning <span class="RktVal">'</span><span class="RktVal">eval</span>,
|
|
only because of how I’m generating this documentation, using an
|
|
evaluator to run code snippets in Scribble. Normally this would be
|
|
something like "my-file.rkt".</p></blockquote></blockquote></blockquote><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-source%29%29" class="RktValLink" data-pltdoc="x">syntax-source</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'eval</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-line%29%29" class="RktValLink" data-pltdoc="x">syntax-line</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">11</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-column%29%29" class="RktValLink" data-pltdoc="x">syntax-column</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">0</span></p></td></tr></table></blockquote><p>More interesting is the syntax "stuff" itself. <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3edatum%29%29" class="RktValLink" data-pltdoc="x">syntax->datum</a></span>
|
|
converts it completely into an S-expression:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3edatum%29%29" class="RktValLink" data-pltdoc="x">syntax->datum</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(if<span class="stt"> </span>x<span class="stt"> </span>(list<span class="stt"> </span>"true")<span class="stt"> </span>#f)</span></p></td></tr></table></blockquote><p>Whereas <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-e%29%29" class="RktValLink" data-pltdoc="x">syntax-e</a></span> only goes "one level down". It may return a
|
|
list that has syntax objects:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-e%29%29" class="RktValLink" data-pltdoc="x">syntax-e</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(#<syntax:11:0 if><span class="stt"> </span>#<syntax:11:0 x><span class="stt"> </span>#<syntax:11:0 (list "true")><span class="stt"> </span>#<syntax:11:0 #f>)</span></p></td></tr></table></blockquote><p>Each of those syntax objects could be converted by <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-e%29%29" class="RktValLink" data-pltdoc="x">syntax-e</a></span>,
|
|
and so on recursively—<wbr></wbr>which is what <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3edatum%29%29" class="RktValLink" data-pltdoc="x">syntax->datum</a></span> does.</p><p>In most cases, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3elist%29%29" class="RktValLink" data-pltdoc="x">syntax->list</a></span> gives the same result as
|
|
<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-e%29%29" class="RktValLink" data-pltdoc="x">syntax-e</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3elist%29%29" class="RktValLink" data-pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'(#<syntax:11:0 if><span class="stt"> </span>#<syntax:11:0 x><span class="stt"> </span>#<syntax:11:0 (list "true")><span class="stt"> </span>#<syntax:11:0 #f>)</span></p></td></tr></table></blockquote><p>(When would <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-e%29%29" class="RktValLink" data-pltdoc="x">syntax-e</a></span> and <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3elist%29%29" class="RktValLink" data-pltdoc="x">syntax->list</a></span> differ? Let’s
|
|
not get side-tracked now.)</p><p>When we want to transform syntax, we’ll generally take the pieces we
|
|
were given, maybe rearrange their order, perhaps change some of the
|
|
pieces, and often introduce brand-new pieces.</p><h4>3.3<tt> </tt><a name="(part._.Actually_transforming_the_input)"></a>Actually transforming the input</h4><p>Let’s write a transformer function that reverses the syntax it was
|
|
given:</p><p><div class="SIntrapara"><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>The <span class="RktSym"><a href="http://docs.racket-lang.org/reference/values.html#%28def._%28%28quote._~23~25kernel%29._values%29%29" class="RktValLink" data-pltdoc="x">values</a></span> at the end of the example allows the
|
|
result to evaluate nicely. Try
|
|
<span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="stt"> </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="RktPn">)</span> to see why it’s handy.</p></blockquote></blockquote></blockquote></div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._datum-~3esyntax%29%29" class="RktValLink" data-pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._reverse%29%29" class="RktValLink" data-pltdoc="x">reverse</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cdr%29%29" class="RktValLink" data-pltdoc="x">cdr</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3edatum%29%29" class="RktValLink" data-pltdoc="x">syntax->datum</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="hspace"> </span><span class="RktVal">"backwards"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/values.html#%28def._%28%28quote._~23~25kernel%29._values%29%29" class="RktValLink" data-pltdoc="x">values</a></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></div></p><p>Understand Yoda, can we. Great, but how does this work?</p><p>First we take the input syntax, and give it to
|
|
<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3edatum%29%29" class="RktValLink" data-pltdoc="x">syntax->datum</a></span>. This converts the syntax into a plain old
|
|
list:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3edatum%29%29" class="RktValLink" data-pltdoc="x">syntax->datum</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">reverse-me</span><span class="hspace"> </span><span class="RktVal">"backwards"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/values.html#%28def._%28%28quote._~23~25kernel%29._values%29%29" class="RktValLink" data-pltdoc="x">values</a></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"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cdr%29%29" class="RktValLink" data-pltdoc="x">cdr</a></span> slices off the first item of the list,
|
|
<span class="RktSym">reverse-me</span>, leaving the remainder:
|
|
<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"><a href="http://docs.racket-lang.org/reference/values.html#%28def._%28%28quote._~23~25kernel%29._values%29%29" class="RktValLink" data-pltdoc="x">values</a></span><span class="RktPn">)</span>. Passing that to
|
|
<span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._reverse%29%29" class="RktValLink" data-pltdoc="x">reverse</a></span> changes it to <span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/values.html#%28def._%28%28quote._~23~25kernel%29._values%29%29" class="RktValLink" data-pltdoc="x">values</a></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" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._reverse%29%29" class="RktValLink" data-pltdoc="x">reverse</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cdr%29%29" class="RktValLink" data-pltdoc="x">cdr</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">reverse-me</span><span class="hspace"> </span><span class="RktVal">"backwards"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="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 class="stt"> </span>"backwards")</span></p></td></tr></table></blockquote><p>Finally we use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._datum-~3esyntax%29%29" class="RktValLink" data-pltdoc="x">datum->syntax</a></span> to convert this back to
|
|
<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._syntax%29%29" class="RktStxLink" data-pltdoc="x">syntax</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._datum-~3esyntax%29%29" class="RktValLink" data-pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktVal">#f</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">values</span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"backwards"</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#<syntax (values "i" "am" "backwards")></span></p></td></tr></table></blockquote><p>That’s what our transformer function gives back to the Racket
|
|
compiler, and <span style="font-style: italic">that</span> syntax is evaluated:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/values.html#%28def._%28%28quote._~23~25kernel%29._values%29%29" class="RktValLink" data-pltdoc="x">values</a></span><span class="hspace"> </span><span class="RktVal">"i"</span><span class="hspace"> </span><span class="RktVal">"am"</span><span class="hspace"> </span><span class="RktVal">"backwards"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"i"</span></p></td></tr><tr><td><p><span class="RktRes">"am"</span></p></td></tr><tr><td><p><span class="RktRes">"backwards"</span></p></td></tr></table></blockquote><h4>3.4<tt> </tt><a name="(part._.Compile_time_vs__run_time)"></a>Compile time vs. run time</h4><p><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pipeports.html#%28def._%28%28quote._~23~25kernel%29._make-pipe%29%29" class="RktValLink" data-pltdoc="x">make-pipe</a></span><span class="RktPn">)</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktCmt">;Ce</span><span class="hspace"> </span><span class="RktCmt">n'est</span><span class="hspace"> </span><span class="RktCmt">pas</span><span class="hspace"> </span><span class="RktCmt">le</span><span class="hspace"> </span><span class="RktCmt">temps</span><span class="hspace"> </span><span class="RktCmt">d'exécution</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._syntax%29%29" class="RktStxLink" data-pltdoc="x">#'</a></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktMeta"></span></td></tr></table></p><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 called by Racket as part of the process of
|
|
parsing, expanding, and compiling our program. In other words, our
|
|
syntax transformer function is evaluated at compile time.</p><p>This aspect of macros lets you do things that simply aren’t possible
|
|
in normal code. One of the classic examples is something like the
|
|
Racket form, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28quote._~23~25kernel%29._if%29%29" class="RktStxLink" data-pltdoc="x">if</a></span>:</p><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28quote._~23~25kernel%29._if%29%29" class="RktStxLink" data-pltdoc="x">if</a></span><span class="stt"> </span><span class="RktSym"><condition></span><span class="stt"> </span><span class="RktSym"><true-expression></span><span class="stt"> </span><span class="RktSym"><false-expression></span><span class="RktPn">)</span></p><p>If we implemented <span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28quote._~23~25kernel%29._if%29%29" class="RktStxLink" data-pltdoc="x">if</a></span> as a function, all of the arguments
|
|
would be evaluated before being provided to the function.</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._cond%29%29" class="RktStxLink" data-pltdoc="x">cond</a></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._else%29%29" class="RktStxLink" data-pltdoc="x">else</a></span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace"> </span><span class="RktVal">#t</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktVal">"true"</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>That seems to work. However, how about this:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28lib._racket%2Fprivate%2Fmisc..rkt%29._displayln%29%29" class="RktValLink" data-pltdoc="x">displayln</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace"> </span><span class="RktVal">#t</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" cellpadding="0"><tr><td><p><span class="RktOut">true</span></p></td></tr><tr><td><p><span class="RktOut">false</span></p></td></tr></table></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>One answer is that functional programming is good, and
|
|
side-effects are bad. But avoiding side-effects isn’t always
|
|
practical.</p></blockquote></blockquote></blockquote><p>Oops. Because the expressions have a side-effect, it’s obvious that
|
|
they are both evaluated. And that could be a problem—<wbr></wbr>what if the
|
|
side-effect includes deleting a file on disk? You wouldn’t want
|
|
<span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28quote._~23~25kernel%29._if%29%29" class="RktStxLink" data-pltdoc="x">if</a></span><span class="stt"> </span><span class="RktSym">user-wants-file-deleted?</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Filesystem.html#%28def._%28%28quote._~23~25kernel%29._delete-file%29%29" class="RktValLink" data-pltdoc="x">delete-file</a></span><span class="RktPn">)</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span><span class="RktPn">)</span><span class="RktPn">)</span> to delete
|
|
a file even when <span class="RktSym">user-wants-file-deleted?</span> is <span class="RktVal">#f</span>.</p><p>So this simply can’t work as a plain function. However a syntax
|
|
transformer can rearrange the syntax – rewrite the code – at compile
|
|
time. The pieces of syntax are moved around, but they aren’t actually
|
|
evaluated until run time.</p><p>Here is one way to do this:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3elist%29%29" class="RktValLink" data-pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._datum-~3esyntax%29%29" class="RktValLink" data-pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadr%29%29" class="RktValLink" data-pltdoc="x">cadr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._caddr%29%29" class="RktValLink" data-pltdoc="x">caddr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadddr%29%29" class="RktValLink" data-pltdoc="x">cadddr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktVal">#t</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktOut">true</span></p></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktVal">#f</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktOut">false</span></p></td></tr><tr><td><p><span class="RktRes">"false"</span></p></td></tr></table></blockquote><p>That gave the right answer. But how? Let’s pull out the transformer
|
|
function itself, and see what it did. We start with an example of some
|
|
input syntax:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28lib._racket%2Fprivate%2Fmisc..rkt%29._displayln%29%29" class="RktValLink" data-pltdoc="x">displayln</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">#<syntax:32:0 (our-if-v2 #t "true" "false")></span></p></td></tr></table></blockquote><p>1. We take the original syntax, and use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3elist%29%29" class="RktValLink" data-pltdoc="x">syntax->list</a></span> to
|
|
change it into a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._list%29%29" class="RktValLink" data-pltdoc="x">list</a></span> of syntax objects:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3elist%29%29" class="RktValLink" data-pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#%28def._%28%28lib._racket%2Fprivate%2Fmisc..rkt%29._displayln%29%29" class="RktValLink" data-pltdoc="x">displayln</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">(#<syntax:32:0 our-if-v2> #<syntax:32:0 #t> #<syntax:32:0 "true"> #<syntax:32:0 "false">)</span></p></td></tr></table></blockquote><p>2. To change this into a Racket <span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._cond%29%29" class="RktStxLink" data-pltdoc="x">cond</a></span> form, we need to take
|
|
the three interesting pieces—<wbr></wbr>the condition, true-expression, and
|
|
false-expression—<wbr></wbr>from the list using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadr%29%29" class="RktValLink" data-pltdoc="x">cadr</a></span>, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._caddr%29%29" class="RktValLink" data-pltdoc="x">caddr</a></span>,
|
|
and <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadddr%29%29" class="RktValLink" data-pltdoc="x">cadddr</a></span> and arrange them into a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._cond%29%29" class="RktStxLink" data-pltdoc="x">cond</a></span> form:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadr%29%29" class="RktValLink" data-pltdoc="x">cadr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._caddr%29%29" class="RktValLink" data-pltdoc="x">caddr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadddr%29%29" class="RktValLink" data-pltdoc="x">cadddr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span><span class="RktVal">)</span></td></tr></table></blockquote><p>3. Finally, we change that into <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._syntax%29%29" class="RktStxLink" data-pltdoc="x">syntax</a></span> using
|
|
<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._datum-~3esyntax%29%29" class="RktValLink" data-pltdoc="x">datum->syntax</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._datum-~3esyntax%29%29" class="RktValLink" data-pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadr%29%29" class="RktValLink" data-pltdoc="x">cadr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._caddr%29%29" class="RktValLink" data-pltdoc="x">caddr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadddr%29%29" class="RktValLink" data-pltdoc="x">cadddr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktRes">#<syntax (cond (#t "true") (else "fals...></span></p></td></tr></table></blockquote><p>So that works, but using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadddr%29%29" class="RktValLink" data-pltdoc="x">cadddr</a></span> etc. to destructure a list is
|
|
painful and error-prone. Maybe you know Racket’s <span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#%28form._%28%28lib._racket%2Fmatch..rkt%29._match%29%29" class="RktStxLink" data-pltdoc="x">match</a></span>?
|
|
Using that would let us do pattern-matching.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Notice that we don’t care about the first item in the
|
|
syntax list. We didn’t take <span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._car%29%29" class="RktValLink" data-pltdoc="x">car</a></span><span class="stt"> </span><span class="RktSym">xs</span><span class="RktPn">)</span> in our-if-v2, and we
|
|
didn’t use <span class="RktSym">name</span> when we used pattern-matching. In general, a
|
|
syntax transformer won’t care about that, because it is the name of
|
|
the transformer binding. In other words, a macro usually doesn’t care
|
|
about its own name.</p></blockquote></blockquote></blockquote><p>Instead of:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3elist%29%29" class="RktValLink" data-pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._datum-~3esyntax%29%29" class="RktValLink" data-pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadr%29%29" class="RktValLink" data-pltdoc="x">cadr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._caddr%29%29" class="RktValLink" data-pltdoc="x">caddr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cadddr%29%29" class="RktValLink" data-pltdoc="x">cadddr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr></table></blockquote><p>We can write:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#%28form._%28%28lib._racket%2Fmatch..rkt%29._match%29%29" class="RktStxLink" data-pltdoc="x">match</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3elist%29%29" class="RktValLink" data-pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._list%29%29" class="RktValLink" data-pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._datum-~3esyntax%29%29" class="RktValLink" data-pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">true-expr</span><span class="RktVal">]</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">false-expr</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr></table></blockquote><p>Great. Now let’s try using it:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">match: undefined;</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">cannot reference an identifier before its definition</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in module: 'program</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">phase: 1</span></p></td></tr></table></blockquote><p>Oops. It’s complaining that <span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#%28form._%28%28lib._racket%2Fmatch..rkt%29._match%29%29" class="RktStxLink" data-pltdoc="x">match</a></span> isn’t defined.</p><p>Our 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—<wbr></wbr>not the full <span class="RktSym">racket</span>.</p><p>Anything beyond <span class="RktSym">racket/base</span>, we have to require
|
|
ourselves—<wbr></wbr>and require it for compile time using the
|
|
<span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for-syntax%29%29" class="RktStxLink" data-pltdoc="x">for-syntax</a></span> form of <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span>.</p><p>In this case, instead of using plain <span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="stt"> </span><span class="RktSym">racket/match</span><span class="RktPn">)</span>,
|
|
we want <span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for-syntax%29%29" class="RktStxLink" data-pltdoc="x">for-syntax</a></span><span class="stt"> </span><span class="RktSym">racket/match</span><span class="RktPn">)</span><span class="RktPn">)</span>—<wbr></wbr>the
|
|
<span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for-syntax%29%29" class="RktStxLink" data-pltdoc="x">for-syntax</a></span> part meaning, "for compile time".</p><p>So let’s try that:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for-syntax%29%29" class="RktStxLink" data-pltdoc="x">for-syntax</a></span><span class="hspace"> </span><span class="RktSym">racket/match</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match-v2</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#%28form._%28%28lib._racket%2Fmatch..rkt%29._match%29%29" class="RktStxLink" data-pltdoc="x">match</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-~3elist%29%29" class="RktValLink" data-pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._list%29%29" class="RktValLink" data-pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29.__%29%29" class="RktStxLink" data-pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._datum-~3esyntax%29%29" class="RktValLink" data-pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">`</span><span class="RktVal">(</span><span class="RktVal">cond</span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktRdr">,</span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">true-expr</span><span class="RktVal">]</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">false-expr</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match-v2</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>Joy.</p><h4>3.5<tt> </tt><a name="(part._begin-for-syntax)"></a><span class="RktSym"><a href="http://docs.racket-lang.org/reference/begin.html#%28form._%28%28quote._~23~25kernel%29._begin-for-syntax%29%29" class="RktStxLink" data-pltdoc="x">begin-for-syntax</a></span></h4><p>We used <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for-syntax%29%29" class="RktStxLink" data-pltdoc="x">for-syntax</a></span> to <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span> the
|
|
<span class="RktSym">racket/match</span> module because we needed to use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#%28form._%28%28lib._racket%2Fmatch..rkt%29._match%29%29" class="RktStxLink" data-pltdoc="x">match</a></span>
|
|
at compile time.</p><p>What if we wanted to define our own helper function to be used by a
|
|
macro? One way to do that is put it in another module, and
|
|
<span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._require%29%29" class="RktStxLink" data-pltdoc="x">require</a></span> it using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for-syntax%29%29" class="RktStxLink" data-pltdoc="x">for-syntax</a></span>, just like we did with
|
|
the <span class="RktSym">racket/match</span> module.</p><p>If instead we want to put the helper in the same module, we can’t
|
|
simply <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span> it and use it—<wbr></wbr>the definition would exist at
|
|
run time, but we need it at compile time. The answer is to put the
|
|
definition of the helper function(s) inside <span class="RktSym"><a href="http://docs.racket-lang.org/reference/begin.html#%28form._%28%28quote._~23~25kernel%29._begin-for-syntax%29%29" class="RktStxLink" data-pltdoc="x">begin-for-syntax</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/begin.html#%28form._%28%28quote._~23~25kernel%29._begin-for-syntax%29%29" class="RktStxLink" data-pltdoc="x">begin-for-syntax</a></span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">my-helper-function</span><span class="hspace"> </span><span class="RktSym">....</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktSym">....</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">macro-using-my-helper-function</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">my-helper-function</span><span class="hspace"> </span><span class="RktSym">....</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktSym">....</span><span class="RktPn">)</span></td></tr></table></blockquote><p>In the simple case, we can also use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-for-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-for-syntax</a></span>, which
|
|
composes <span class="RktSym"><a href="http://docs.racket-lang.org/reference/begin.html#%28form._%28%28quote._~23~25kernel%29._begin-for-syntax%29%29" class="RktStxLink" data-pltdoc="x">begin-for-syntax</a></span> and <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-for-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-for-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">my-helper-function</span><span class="hspace"> </span><span class="RktSym">....</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktSym">....</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29" class="RktStxLink" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">macro-using-my-helper-function</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">my-helper-function</span><span class="hspace"> </span><span class="RktSym">....</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktSym">....</span><span class="RktPn">)</span></td></tr></table></blockquote><p>To review:</p><ul><li><p>Syntax transformers work at compile time, not run time. The good
|
|
news is this means we can do things like rearrange the pieces of
|
|
syntax without evaluating them. We can implement forms like
|
|
<span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#%28form._%28%28quote._~23~25kernel%29._if%29%29" class="RktStxLink" data-pltdoc="x">if</a></span> that simply couldn’t work properly as run time functions.</p></li><li><p>More good news is that there isn’t some special, weird language
|
|
for writing syntax transformers. We can write these transformer
|
|
functions using the Racket language we already know and love.</p></li><li><p>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.</p><ul><li><p>For example only <span class="RktSym">racket/base</span> is required for us
|
|
automatically. If we need other modules, we have to require them, and
|
|
do so <span style="font-style: italic">for compile time</span> using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for-syntax%29%29" class="RktStxLink" data-pltdoc="x">for-syntax</a></span>.</p></li><li><p>Similarly, if we want to define helper functions in the same
|
|
file/module as the macros that use them, we need to wrap the
|
|
definitions inside a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/begin.html#%28form._%28%28quote._~23~25kernel%29._begin-for-syntax%29%29" class="RktStxLink" data-pltdoc="x">begin-for-syntax</a></span> form. Doing so makes
|
|
them available at compile time.</p></li></ul></li></ul><div class="navsetbottom"><span class="navleft"><div class="nosearchform"></div> </span><span class="navright"> <a href="Our_plan_of_attack.html" title="backward to "2 Our plan of attack"" data-pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" data-pltdoc="x">up</a> <a href="pattern-matching.html" title="forward to "4 Pattern matching: syntax-case and syntax-rules"" data-pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> |