commit d1af14bbea3e913080e9a59804affc2b597efb3f parent 1dd377cc5f3fdef23f2b4c5c07d52e6be9135ac0 Author: Greg Hendershott <greghendershott@gmail.com> Date: Tue, 13 Nov 2012 13:57:47 -0500 Gen htmls Diffstat:
| A | Epilogue.html | | | 10 | ++++++++++ |
| A | Our_plan_of_attack.html | | | 23 | +++++++++++++++++++++++ |
| A | Preface.html | | | 25 | +++++++++++++++++++++++++ |
| A | References_and_Acknowledgments.html | | | 35 | +++++++++++++++++++++++++++++++++++ |
| A | Robust_macros__syntax-parse.html | | | 32 | ++++++++++++++++++++++++++++++++ |
| A | Syntax_parameters.html | | | 25 | +++++++++++++++++++++++++ |
| A | Transform_.html | | | 103 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | What_s_the_point_of_splicing-let_.html | | | 12 | ++++++++++++ |
| A | index.html | | | 4 | ++++ |
| A | pattern-matching.html | | | 122 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
10 files changed, 391 insertions(+), 0 deletions(-)
diff --git a/Epilogue.html b/Epilogue.html @@ -0,0 +1,9 @@ +<!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>9 Epilogue</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" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" pltdoc="x">Fear of Macros</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="Preface.html" class="tocviewlink" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="Transform_.html" class="tocviewlink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="Syntax_parameters.html" class="tocviewlink" 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" 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" 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" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="" class="tocviewselflink" pltdoc="x">Epilogue</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"> </span><span class="navright"><a href="References_and_Acknowledgments.html" title="backward to "8 References and Acknowledgments"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <span class="nonavigation">next →</span></span> </div><h3>9<tt> </tt><a name="(part._.Epilogue)"></a>Epilogue</h3><blockquote class="SCentered"><p>"Before I had studied Chan (Zen) for thirty years, I saw mountains as +mountains, and rivers as rivers. When I arrived at a more intimate +knowledge, I came to the point where I saw that mountains are not +mountains, and rivers are not rivers. But now that I have got its very +substance I am at rest. For it’s just that I see mountains once again +as mountains, and rivers once again as rivers"</p><p><span class="Smaller">–Buddhist saying originally formulated by Qingyuan Weixin, +later translated by D.T. Suzuki in his <span style="font-style: italic">Essays in Zen +Buddhism</span>.</span></p></blockquote><p>Translated into Racket:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/cont.html#(def._((quote._~23~25kernel)._dynamic-wind))" class="RktValLink" pltdoc="x">dynamic-wind</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._and))" class="RktStxLink" pltdoc="x">and</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._eq~3f))" class="RktValLink" pltdoc="x">eq?</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">mountains</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">mountains</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._eq~3f))" class="RktValLink" pltdoc="x">eq?</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">rivers</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">rivers</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._not))" class="RktValLink" pltdoc="x">not</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._and))" class="RktStxLink" pltdoc="x">and</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._eq~3f))" class="RktValLink" pltdoc="x">eq?</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">mountains</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">mountains</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._eq~3f))" class="RktValLink" pltdoc="x">eq?</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">rivers</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">rivers</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._and))" class="RktStxLink" pltdoc="x">and</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._eq~3f))" class="RktValLink" pltdoc="x">eq?</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">mountains</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">mountains</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._eq~3f))" class="RktValLink" pltdoc="x">eq?</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">rivers</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">rivers</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><div class="navsetbottom"><span class="navleft"> </span><span class="navright"><a href="References_and_Acknowledgments.html" title="backward to "8 References and Acknowledgments"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <span class="nonavigation">next →</span></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file diff --git a/Our_plan_of_attack.html b/Our_plan_of_attack.html @@ -0,0 +1,22 @@ +<!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>2 Our plan of attack</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" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" pltdoc="x">Fear of Macros</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="Preface.html" class="tocviewlink" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="" class="tocviewselflink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="Transform_.html" class="tocviewlink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="Syntax_parameters.html" class="tocviewlink" 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" 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" 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" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" pltdoc="x">Epilogue</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"> </span><span class="navright"><a href="Preface.html" title="backward to "1 Preface"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Transform_.html" title="forward to "3 Transform!"" pltdoc="x">next →</a></span> </div><h3>2<tt> </tt><a name="(part._.Our_plan_of_attack)"></a>Our plan of attack</h3><p>The macro system you will mostly want to use for production-quality +macros is called <span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Parsing_Syntax.html#(form._((lib._syntax%2Fparse..rkt)._syntax-parse))" class="RktStxLink" pltdoc="x">syntax-parse</a></span>. And don’t worry, we’ll get to +that soon.</p><p>But if we start there, you’re likely to feel overwhelmed by concepts +and terminology, and get very confused. I did.</p><p>1. Instead let’s start with the basics: A syntax object and a function +to change it—<wbr></wbr>a "transformer". We’ll work at that level for awhile to +get comfortable and to de-mythologize this whole macro business.</p><p>2. Soon we’ll realize that pattern-matching would make life +easier. We’ll learn about <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span> and its shorthand +cousin, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></span>. We’ll discover we can get +confused if we want to munge pattern variables before sticking them +back in the template, and learn how to do that.</p><p>3. At this point we’ll be able to write many useful macros. But, what +if we want to write the ever-popular anaphoric if, with a "magic +variable"? It turns out we’ve been protected from making certain kind +of mistakes. When we want to do this kind of thing on purpose, we use +a 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 +advocating "hygiene"—<wbr></wbr>we’ll just stipulate that it’s good.]</p><p>4. Finally, we’ll realize that our macros could be smarter when +they’re used in error. Normal Racket functions optionally can have +contracts and types. These catch usage mistakes and provide clear, +useful error messages. It would be great if there were something +similar for macro. There is. One of the more-recent Racket macro +enhancements is <span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Parsing_Syntax.html#(form._((lib._syntax%2Fparse..rkt)._syntax-parse))" class="RktStxLink" pltdoc="x">syntax-parse</a></span>.</p><div class="navsetbottom"><span class="navleft"> </span><span class="navright"><a href="Preface.html" title="backward to "1 Preface"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Transform_.html" title="forward to "3 Transform!"" pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file diff --git a/Preface.html b/Preface.html @@ -0,0 +1,24 @@ +<!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>1 Preface</title><link rel="stylesheet" type="text/css" href="scribble.css" title="default" /><link rel="stylesheet" type="text/css" href="scribble-style.css" title="default" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" pltdoc="x">Fear of Macros</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="" class="tocviewselflink" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="Transform_.html" class="tocviewlink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="Syntax_parameters.html" class="tocviewlink" 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" 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" 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" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" pltdoc="x">Epilogue</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"> </span><span class="navright"><a href="index.html" title="backward to "Fear of Macros"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Our_plan_of_attack.html" title="forward to "2 Our plan of attack"" pltdoc="x">next →</a></span> </div><h3>1<tt> </tt><a name="(part._.Preface)"></a>Preface</h3><p>I learned Racket after 25 years of mostly using C and C++.</p><p>Some psychic whiplash resulted.</p><p>"All the parentheses" was actually not a big deal. Instead, the first +mind warp was functional programming. Before long I wrapped my brain +around it, and went on to become comfortable and effective with many +other aspects and features of Racket.</p><p>But two final frontiers remained: Macros and continuations.</p><p>I found that simple macros were easy and understandable, plus there +were many good tutorials available. But the moment I stepped past +routine pattern-matching, I kind of fell off a cliff into a +terminology soup. I marinaded myself in material, hoping it would +eventually sink in after enough re-readings. I even found myself using +trial and error, rather than having a clear mental model what was +going on. Gah.</p><p>I’m starting to write this at the point where the shapes are slowly +emerging from the fog.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>If you have any corrections, criticisms, complaints, or whatever, +<a href="https://github.com/greghendershott/fear-of-macros/issues">please +let me know</a>.</p></blockquote></blockquote></blockquote><p>My primary motive is selfish. Explaining something forces me to learn +it more thoroughly. Plus if I write something with mistakes, other +people will be eager to point them out and correct me. Is that a +social-engineering variation of meta-programming? Next question, +please. :)</p><p>Finally I do hope it may help other people who have a similar +background and/or learning style as me.</p><p>I want to show how Racket macro features have evolved as solutions to +problems or annoyances. I learn more quickly and deeply when I +discover the answer to a question I already have, or find the solution +to a problem whose pain I already feel. Therefore I’ll give you the +questions and problems first, so that you can better appreciate and +understand the answers and solutions.</p><div class="navsetbottom"><span class="navleft"> </span><span class="navright"><a href="index.html" title="backward to "Fear of Macros"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Our_plan_of_attack.html" title="forward to "2 Our plan of attack"" pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file diff --git a/References_and_Acknowledgments.html b/References_and_Acknowledgments.html @@ -0,0 +1,34 @@ +<!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>8 References and Acknowledgments</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" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" pltdoc="x">Fear of Macros</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="Preface.html" class="tocviewlink" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="Transform_.html" class="tocviewlink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="Syntax_parameters.html" class="tocviewlink" 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" 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" pltdoc="x">Robust macros:<span class="mywbr"> </span> syntax-<wbr></wbr>parse</a></td></tr><tr><td align="right">8 </td><td><a href="" class="tocviewselflink" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" pltdoc="x">Epilogue</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"> </span><span class="navright"><a href="Robust_macros__syntax-parse.html" title="backward to "7 Robust macros: syntax-parse"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Epilogue.html" title="forward to "9 Epilogue"" pltdoc="x">next →</a></span> </div><h3>8<tt> </tt><a name="(part._.References_and_.Acknowledgments)"></a>References and Acknowledgments</h3><p>Eli Barzliay’s blog post, +<a href="http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html">Writing +‘syntax-case’ Macros</a>, helped me understand many key details and +concepts. It also inspired me to use a "bottom-up" approach. However +he wrote for a specific audience. If you’re not already familiar with +un-hygienic defmacro style macros, it may seem slightly weird to the +extent it’s trying to convince you to change an opinion you don’t +have. I’m writing for people who don’t have any opinion about macros +at all, except maybe that macros seem scary and daunting.</p><p>Eli 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><p>Matthew Flatt’s +<a href="http://www.cs.utah.edu/plt/publications/macromod.pdf">Composable +and Compilable Macros: You Want it When?</a> explains how Racket handles +compile time vs. run time.</p><p><a href="http://www.scheme.com/tspl4/syntax.html#./syntax:h0">Chapter +8</a> of <span style="font-style: italic">The Scheme Programming Language</span> by Kent Dybvig +explains <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-rules))" class="RktStxLink" pltdoc="x">syntax-rules</a></span> and <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span>. Although +more "formal" in tone, you may find it helpful to read it. You never +know which explanation or examples of something will click for you.</p><p>After initially wondering if I was asking the wrong question and +conflating two different issues :), Shriram Krishnamurthi looked at an +early draft and encouraged me to keep going. Sam Tobin-Hochstadt and +Robby Findler also encouraged me. Matthew Flatt showed me how to make +a Scribble <span class="RktSym">interaction</span> print <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" pltdoc="x">syntax</a></span> as +<span class="RktVal">"syntax"</span> rather than as <span class="RktVal">"#'"</span>. Jay McCarthy helped me +catch some mistakes and confusions. Jon Rafkind pointed out some +problems. Kieron Hardy reported a font issue and some typos.</p><p>Finally, I noticed something strange. After writing much of this, when +I returned to some parts of the Racket documentation, I noticed it had +improved since I last read it. Of course, it was the same. I’d +changed. It’s interesting how much of what we already know is +projected between the lines. My point is, the Racket documentation is +very good. The <span style="font-style: italic">Guide</span> provides helpful examples and +tutorials. The <span style="font-style: italic">Reference</span> is very clear and precise.</p><div class="navsetbottom"><span class="navleft"> </span><span class="navright"><a href="Robust_macros__syntax-parse.html" title="backward to "7 Robust macros: syntax-parse"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Epilogue.html" title="forward to "9 Epilogue"" pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file diff --git a/Robust_macros__syntax-parse.html b/Robust_macros__syntax-parse.html @@ -0,0 +1,31 @@ +<!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>7 Robust macros: syntax-parse</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" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" 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" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="Transform_.html" class="tocviewlink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="Syntax_parameters.html" class="tocviewlink" 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" 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="" class="tocviewselflink" 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" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" 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>7 </td><td><a href="" class="tocviewselflink" pltdoc="x">Robust macros:<span class="mywbr"> </span> syntax-<wbr></wbr>parse</a></td></tr></table><div class="tocviewsublistbottom" style="display: none;" id="tocview_1"><table cellspacing="0" cellpadding="0"><tr><td align="right">7.1 </td><td><a href="#(part._.Error-handling_strategies_for_functions)" class="tocviewlink" pltdoc="x">Error-<wbr></wbr>handling strategies for functions</a></td></tr><tr><td align="right">7.2 </td><td><a href="#(part._.Error-handling_strategies_for_macros)" class="tocviewlink" pltdoc="x">Error-<wbr></wbr>handling strategies for macros</a></td></tr><tr><td align="right">7.3 </td><td><a href="#(part._.Using_syntax_parse)" class="tocviewlink" pltdoc="x">Using <span class="RktSym">syntax/<span class="mywbr"> </span>parse</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">7.1<tt> </tt></span><a href="#(part._.Error-handling_strategies_for_functions)" class="tocsubseclink" pltdoc="x">Error-<wbr></wbr>handling strategies for functions</a></td></tr><tr><td><span class="tocsublinknumber">7.2<tt> </tt></span><a href="#(part._.Error-handling_strategies_for_macros)" class="tocsubseclink" pltdoc="x">Error-<wbr></wbr>handling strategies for macros</a></td></tr><tr><td><span class="tocsublinknumber">7.3<tt> </tt></span><a href="#(part._.Using_syntax_parse)" class="tocsubseclink" pltdoc="x">Using <span class="RktSym">syntax/<span class="mywbr"> </span>parse</span></a></td></tr></table></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"> </span><span class="navright"><a href="What_s_the_point_of_splicing-let_.html" title="backward to "6 What's the point of splicing-let?"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="References_and_Acknowledgments.html" title="forward to "8 References and Acknowledgments"" pltdoc="x">next →</a></span> </div><h3>7<tt> </tt><a name="(part._.Robust_macros__syntax-parse)"></a>Robust macros: syntax-parse</h3><p>Functions can be used in error. So can macros.</p><h4>7.1<tt> </tt><a name="(part._.Error-handling_strategies_for_functions)"></a>Error-handling strategies for functions</h4><p>With plain old functions, we have several choices how to handle +misuse.</p><p>1. Don’t check at all.</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">misuse</span><span class="hspace"> </span><span class="RktSym">s</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#(def._((quote._~23~25kernel)._string-append))" class="RktValLink" pltdoc="x">string-append</a></span><span class="hspace"> </span><span class="RktSym">s</span><span class="hspace"> </span><span class="RktVal">" snazzy suffix"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">User of the function:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">misuse</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">string-append: contract violation</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">expected: string?</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">given: 0</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">argument position: 1st</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">other arguments...:</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">" snazzy suffix"</span></p></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">I guess I goofed, but </span><span class="RktCmt">–</span><span class="RktCmt"> what is this "string-append" of which you</span></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">speak??</span></td></tr></table></blockquote><p>The problem is that the resulting error message will be confusing. Our +user thinks they’re calling <span class="RktSym">misuse</span>, but is getting an error +message from <span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#(def._((quote._~23~25kernel)._string-append))" class="RktValLink" pltdoc="x">string-append</a></span>. In this simple example they +could probably guess what’s happening, but in most cases they won’t.</p><p>2. Write some error handling code.</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">misuse</span><span class="hspace"> </span><span class="RktSym">s</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/when_unless.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._unless))" class="RktStxLink" pltdoc="x">unless</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#(def._((quote._~23~25kernel)._string~3f))" class="RktValLink" pltdoc="x">string?</a></span><span class="hspace"> </span><span class="RktSym">s</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._error))" class="RktValLink" pltdoc="x">error</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">misuse</span><span class="hspace"> </span><span class="RktVal">"expected a string, but got ~a"</span><span class="hspace"> </span><span class="RktSym">s</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#(def._((quote._~23~25kernel)._string-append))" class="RktValLink" pltdoc="x">string-append</a></span><span class="hspace"> </span><span class="RktSym">s</span><span class="hspace"> </span><span class="RktVal">" snazzy suffix"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">User of the function:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">misuse</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">misuse: expected a string, but got 0</span></p></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">I goofed, and understand why! It</span><span class="RktCmt">'</span><span class="RktCmt">s a shame the writer of the</span></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">function had to work so hard to tell me.</span></td></tr></table></blockquote><p>Unfortunately the error code tends to overwhelm and/or obscure our +function definition. Also, the error message is good but not +great. Improving it would require even more error code.</p><p>3. Use a contract.</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/attaching-contracts-to-values.html#(form._((lib._racket%2Fcontract%2Fregion..rkt)._define%2Fcontract))" class="RktStxLink" pltdoc="x">define/contract</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">misuse</span><span class="hspace"> </span><span class="RktSym">s</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#(def._((quote._~23~25kernel)._string~3f))" class="RktValLink" pltdoc="x">string?</a></span><span class="hspace"> </span><span class="RktPn">. </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/function-contracts.html#(form._((lib._racket%2Fcontract%2Fbase..rkt)._-~3e))" class="RktStxLink" pltdoc="x"><span class="nobreak">-></span></a></span><span class="RktPn"> .</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#(def._((quote._~23~25kernel)._string~3f))" class="RktValLink" pltdoc="x">string?</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#(def._((quote._~23~25kernel)._string-append))" class="RktValLink" pltdoc="x">string-append</a></span><span class="hspace"> </span><span class="RktSym">s</span><span class="hspace"> </span><span class="RktVal">" snazzy suffix"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">User of the function:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">misuse</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">misuse: contract violation</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">expected: string?, given: 0</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: the 1st argument of</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">(-> string? string?)</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">contract from: (function misuse)</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">blaming: program</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">at: eval:130.0</span></p></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">I goofed, and understand why! I</span><span class="RktCmt">'</span><span class="RktCmt">m happier, and I hear the writer of</span></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">the function is happier, too.</span></td></tr></table></blockquote><p>This is the best of both worlds.</p><p>The contract is a simple and concise. Even better, it’s +declarative. We say what we want, without needing to spell out what to +do.</p><p>On the other hand the user of our function gets a very detailed error +message. Plus, the message is in a standard, familiar format.</p><p>4. Use Typed Racket.</p><p><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace"> </span><span class="RktMeta"></span><a href="http://docs.racket-lang.org/ts-reference/index.html" class="RktModLink" pltdoc="x"><span class="RktSym">typed/racket</span></a><span class="RktMeta"></span></td></tr></table></blockquote></div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">:</span><span class="hspace"> </span><span class="RktSym">misuse</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">String</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/function-contracts.html#(form._((lib._racket%2Fcontract%2Fbase..rkt)._-~3e))" class="RktStxLink" pltdoc="x"><span class="nobreak">-></span></a></span><span class="hspace"> </span><span class="RktSym">String</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">misuse</span><span class="hspace"> </span><span class="RktSym">s</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#(def._((quote._~23~25kernel)._string-append))" class="RktValLink" pltdoc="x">string-append</a></span><span class="hspace"> </span><span class="RktSym">s</span><span class="hspace"> </span><span class="RktVal">" snazzy suffix"</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">misuse</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">eval:3:0: Type Checker: Expected String, but got Zero</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: (quote 0)</span></p></td></tr></table></blockquote></div></p><p>With respect to error handling, Typed Racket has the same benefits as +contracts. Good.</p><h4>7.2<tt> </tt><a name="(part._.Error-handling_strategies_for_macros)"></a>Error-handling strategies for macros</h4><p>For macros, we have similar choices.</p><p>1. Ignore the possibility of misuse. This choice is even worse for +macros. The default error messages are even less likely to make sense, +much less help our user know what to do.</p><p>2. Write error-handling code. We saw how much this complicated our +macros in our example of <a href="pattern-matching.html#(part._hash..refs)" pltdoc="x">Using dot notation for nested hash lookups</a>. And while we’re still +learning how to write macros, we especially don’t want more cognitive +load and obfuscation.</p><p>3. Use <span class="RktSym">syntax/parse</span>. For macros, this is the equivalent of +using contracts or types for functions. We can declare that input +pattern elements must be certain kinds of things, such as an +identifier. Instead of "types", the kinds are referred to as "syntax +classes". There are predefined syntax classes, plus we can define our +own.</p><h4>7.3<tt> </tt><a name="(part._.Using_syntax_parse)"></a>Using <span class="RktSym">syntax/parse</span></h4><p>November 1, 2012: So here’s the deal. After writing everything up to +this point, I sat down to re-read the documentation for +<span class="RktSym">syntax/parse</span>. It was...very understandable. I didn’t feel +confused.</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktSym"><span</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">style=</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#(form._((quote._~23~25kernel)._quote))" class="RktStxLink" pltdoc="x">'</a></span><span class="RktSym">accent:</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktVal">"Kenau-Reeves"</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/quote.html#(form._((quote._~23~25kernel)._quote))" class="RktStxLink" pltdoc="x">'</a></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._~3e))" class="RktValLink" pltdoc="x">></a></span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktSym">Whoa.</span><span class="RktMeta"></span></td></tr><tr><td><span class="RktMeta"></span><span class="RktSym"></span></span><span class="RktMeta"></span></td></tr></table></blockquote><p>Why? The documentation is written very well. Also, everything up to +this point prepared me to appreciate what <span class="RktSym">syntax/parse</span> does, +and why. That leaves the "how" of using it, which seems pretty +straightforward, so far.</p><p>This might well be a temporary state of me "not knowing what I don’t +know". As I dig in and use it more, maybe I’ll discover something +confusing or tricky. If/when I do, I’ll come back here and update +this.</p><p>But for now I’ll focus on improving the previous parts.</p><div class="navsetbottom"><span class="navleft"> </span><span class="navright"><a href="What_s_the_point_of_splicing-let_.html" title="backward to "6 What's the point of splicing-let?"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="References_and_Acknowledgments.html" title="forward to "8 References and Acknowledgments"" pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file diff --git a/Syntax_parameters.html b/Syntax_parameters.html @@ -0,0 +1,24 @@ +<!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>5 Syntax parameters</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" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" pltdoc="x">Fear of Macros</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="Preface.html" class="tocviewlink" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="Transform_.html" class="tocviewlink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="" class="tocviewselflink" 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" 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" 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" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" pltdoc="x">Epilogue</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"> </span><span class="navright"><a href="pattern-matching.html" title="backward to "4 Pattern matching: syntax-case and syntax-rules"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="What_s_the_point_of_splicing-let_.html" title="forward to "6 What's the point of splicing-let?"" pltdoc="x">next →</a></span> </div><h3>5<tt> </tt><a name="(part._.Syntax_parameters)"></a>Syntax parameters</h3><p>"Anaphoric if" or "aif" is a popular macro example. Instead of writing:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">tmp</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">big-long-calculation</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((quote._~23~25kernel)._if))" class="RktStxLink" pltdoc="x">if</a></span><span class="hspace"> </span><span class="RktSym">tmp</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktVal">#f</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>You could write:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">big-long-calculation</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">it</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktVal">#f</span><span class="RktPn">)</span></td></tr></table></blockquote><p>In other words, when the condition is true, an <span class="RktSym">it</span> identifier +is automatically created and set to the value of the condition. This +should be easy:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">it</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((quote._~23~25kernel)._if))" class="RktStxLink" pltdoc="x">if</a></span><span class="hspace"> </span><span class="RktSym">it</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">true-expr</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((lib._racket%2Fprivate%2Fmisc..rkt)._displayln))" class="RktValLink" pltdoc="x">displayln</a></span><span class="hspace"> </span><span class="RktSym">it</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/void.html#(def._((quote._~23~25kernel)._void))" class="RktValLink" pltdoc="x">void</a></span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">it: undefined;</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">cannot reference an identifier before its definition</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in module: 'program</span></p></td></tr></table></blockquote><p>Wait, what? <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 if our new +syntax introduces a variable that accidentally conflicts with one in +the code surrounding our macro.</p><p>The Racket <span style="font-style: italic">Reference</span> section, +<a href="http://docs.racket-lang.org/reference/syntax-model.html#(part._transformer-model)">Transformer +Bindings</a>, has a good explanation and example. Basically, syntax +has "marks" to preserve lexical scope. This makes your macro behave +like a normal function, for lexical scoping.</p><p>If a normal function defines a variable named <span class="RktSym">x</span>, it won’t +conflict with a variable named <span class="RktSym">x</span> in an outer scope:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktVal">"outer"</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktVal">"inner"</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._printf))" class="RktValLink" pltdoc="x">printf</a></span><span class="hspace"> </span><span class="RktVal">"The inner `x' is ~s\n"</span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._printf))" class="RktValLink" pltdoc="x">printf</a></span><span class="hspace"> </span><span class="RktVal">"The outer `x' is ~s\n"</span><span class="hspace"> </span><span class="RktSym">x</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">The inner `x' is "inner"</span></p></td></tr><tr><td><p><span class="RktOut">The outer `x' is "outer"</span></p></td></tr></table></td></tr></table></blockquote><p>When our macros also respect lexical scoping, it’s easier to write +reliable macros that behave predictably.</p><p>So that’s wonderful default behavior. But <span style="font-style: italic">sometimes</span> we want +to introduce a magic variable on purpose—<wbr></wbr>such as <span class="RktSym">it</span> for +<span class="RktSym">aif</span>.</p><p>The way to do this is with a "syntax parameter", using +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxparam.html#(form._((lib._racket%2Fstxparam..rkt)._define-syntax-parameter))" class="RktStxLink" pltdoc="x">define-syntax-parameter</a></span> and +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxparam.html#(form._((lib._racket%2Fstxparam..rkt)._syntax-parameterize))" class="RktStxLink" pltdoc="x">syntax-parameterize</a></span>. You’re probably familiar with regular +parameters in Racket:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">current-foo</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/parameters.html#(def._((quote._~23~25kernel)._make-parameter))" class="RktValLink" pltdoc="x">make-parameter</a></span><span class="hspace"> </span><span class="RktVal">"some default value"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">current-foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"some default value"</span></p></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/parameters.html#(form._((lib._racket%2Fprivate%2Fmore-scheme..rkt)._parameterize))" class="RktStxLink" pltdoc="x">parameterize</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">current-foo</span><span class="hspace"> </span><span class="RktVal">"I have a new value, for now"</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">current-foo</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktRes">"I have a new value, for now"</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">current-foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"some default value"</span></p></td></tr></table></blockquote><p>That’s a normal parameter. The syntax variation works similarly. The +idea is that we’ll define <span class="RktSym">it</span> to mean an error by +default. Only inside of our <span class="RktSym">aif</span> will it have a meaningful +value:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" pltdoc="x">require</a></span><span class="hspace"> </span><span class="RktSym">racket/stxparam</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxparam.html#(form._((lib._racket%2Fstxparam..rkt)._define-syntax-parameter))" class="RktStxLink" pltdoc="x">define-syntax-parameter</a></span><span class="hspace"> </span><span class="RktSym">it</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._raise-syntax-error))" class="RktValLink" pltdoc="x">raise-syntax-error</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-e))" class="RktValLink" pltdoc="x">syntax-e</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">"can only be used inside aif"</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">tmp</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((quote._~23~25kernel)._if))" class="RktStxLink" pltdoc="x">if</a></span><span class="hspace"> </span><span class="RktSym">tmp</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxparam.html#(form._((lib._racket%2Fstxparam..rkt)._syntax-parameterize))" class="RktStxLink" pltdoc="x">syntax-parameterize</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">it</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxtrans.html#(def._((quote._~23~25kernel)._make-rename-transformer))" class="RktValLink" pltdoc="x">make-rename-transformer</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">tmp</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktVal">10</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((lib._racket%2Fprivate%2Fmisc..rkt)._displayln))" class="RktValLink" pltdoc="x">displayln</a></span><span class="hspace"> </span><span class="RktSym">it</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/void.html#(def._((quote._~23~25kernel)._void))" class="RktValLink" pltdoc="x">void</a></span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktOut">10</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">aif</span><span class="hspace"> </span><span class="RktVal">#f</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((lib._racket%2Fprivate%2Fmisc..rkt)._displayln))" class="RktValLink" pltdoc="x">displayln</a></span><span class="hspace"> </span><span class="RktSym">it</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/void.html#(def._((quote._~23~25kernel)._void))" class="RktValLink" pltdoc="x">void</a></span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>Inside the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxparam.html#(form._((lib._racket%2Fstxparam..rkt)._syntax-parameterize))" class="RktStxLink" pltdoc="x">syntax-parameterize</a></span>, <span class="RktSym">it</span> acts as an alias +for <span class="RktSym">tmp</span>. The alias behavior is created by +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxtrans.html#(def._((quote._~23~25kernel)._make-rename-transformer))" class="RktValLink" pltdoc="x">make-rename-transformer</a></span>.</p><p>If we try to use <span class="RktSym">it</span> outside of an <span class="RktSym">aif</span> form, and +<span class="RktSym">it</span> isn’t otherwise defined, we get an error like we want:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((lib._racket%2Fprivate%2Fmisc..rkt)._displayln))" class="RktValLink" pltdoc="x">displayln</a></span><span class="hspace"> </span><span class="RktSym">it</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">it: can only be used inside aif</span></p></td></tr></table></blockquote><p>But we can still define <span class="RktSym">it</span> as a normal variable:</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">it</span><span class="hspace"> </span><span class="RktVal">10</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktSym">it</span></td></tr><tr><td><p><span class="RktRes">10</span></p></td></tr></table></blockquote><p>For a deeper look, see <a href="http://www.schemeworkshop.org/2011/papers/Barzilay2011.pdf">Keeping it Clean with Syntax Parameters</a>.</p><div class="navsetbottom"><span class="navleft"> </span><span class="navright"><a href="pattern-matching.html" title="backward to "4 Pattern matching: syntax-case and syntax-rules"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="What_s_the_point_of_splicing-let_.html" title="forward to "6 What's the point of splicing-let?"" pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file diff --git a/Transform_.html b/Transform_.html @@ -0,0 +1,102 @@ +<!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>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="scribble-style.css" title="default" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" 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" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="" class="tocviewselflink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="Syntax_parameters.html" class="tocviewlink" 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" 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" 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" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" 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" 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="#(part._.What_is_a_syntax_transformer_)" class="tocviewlink" pltdoc="x">What is a syntax transformer?</a></td></tr><tr><td align="right">3.2 </td><td><a href="#(part._.What_s_the_input_)" class="tocviewlink" pltdoc="x">What’s the input?</a></td></tr><tr><td align="right">3.3 </td><td><a href="#(part._.Actually_transforming_the_input)" class="tocviewlink" pltdoc="x">Actually transforming the input</a></td></tr><tr><td align="right">3.4 </td><td><a href="#(part._.Compile_time_vs__run_time)" class="tocviewlink" pltdoc="x">Compile time vs. run time</a></td></tr><tr><td align="right">3.5 </td><td><a href="#(part._begin-for-syntax)" class="tocviewlink" 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="#(part._.What_is_a_syntax_transformer_)" class="tocsubseclink" pltdoc="x">What is a syntax transformer?</a></td></tr><tr><td><span class="tocsublinknumber">3.2<tt> </tt></span><a href="#(part._.What_s_the_input_)" class="tocsubseclink" pltdoc="x">What’s the input?</a></td></tr><tr><td><span class="tocsublinknumber">3.3<tt> </tt></span><a href="#(part._.Actually_transforming_the_input)" class="tocsubseclink" pltdoc="x">Actually transforming the input</a></td></tr><tr><td><span class="tocsublinknumber">3.4<tt> </tt></span><a href="#(part._.Compile_time_vs__run_time)" class="tocsubseclink" pltdoc="x">Compile time vs. run time</a></td></tr><tr><td><span class="tocsublinknumber">3.5<tt> </tt></span><a href="#(part._begin-for-syntax)" class="tocsubseclink" 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"> </span><span class="navright"><a href="Our_plan_of_attack.html" title="backward to "2 Our plan of attack"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="pattern-matching.html" title="forward to "4 Pattern matching: syntax-case and syntax-rules"" pltdoc="x">next →</a></span> </div><h3>3<tt> </tt><a name="(part._.Transform_)"></a>Transform!</h3><p><table cellspacing="0"><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">YOU ARE INSIDE A ROOM.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">THERE ARE KEYS ON THE GROUND.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">THERE IS A SHINY BRASS LAMP NEARBY.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt"></span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">IF YOU GO THE WRONG WAY, YOU WILL BECOME</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">HOPELESSLY LOST AND CONFUSED.</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt"></span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">> pick up the keys</span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt"></span></span></p></td></tr><tr><td><p><span class="stt"><span class="hspace"> </span><span class="stt">YOU HAVE A SYNTAX TRANSFORMER</span></span></p></td></tr></table></p><h4>3.1<tt> </tt><a name="(part._.What_is_a_syntax_transformer_)"></a>What is a syntax transformer?</h4><p>A syntax transformer is not one of the トランスフォーマ +<a href="http://en.wikipedia.org/wiki/Transformers">transformers</a>.</p><p>Instead, it is 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" class="RktBlk"><tr><td><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">foo</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" 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" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" 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#(form._((quote._~23~25kernel)._quote))" class="RktStxLink" pltdoc="x">quote</a></span>.</p></blockquote></blockquote></blockquote><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktVal">"I am also foo, using #' instead of syntax"</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">quoted-foo</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"I am also foo, using #' instead of syntax"</span></p></td></tr></table></blockquote><p>We’ll use the #’ 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#(def._((lib._racket%2Fprivate%2Fmisc..rkt)._displayln))" class="RktValLink" 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" class="RktBlk"><tr><td><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></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#(def._((lib._racket%2Fprivate%2Fmisc..rkt)._displayln))" class="RktValLink" 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 in the input +syntax into somehing 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" class="RktBlk"><tr><td><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._print))" class="RktValLink" pltdoc="x">print</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/void.html#(def._((quote._~23~25kernel)._void))" class="RktValLink" 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#(def._((quote._~23~25kernel)._print))" class="RktValLink" 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" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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#(form._((quote._~23~25kernel)._if))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._list))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-source))" class="RktValLink" 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 becaue of how I’m generating this documentation, using an +evaluator to run code snippets in Scribble. Normally this would be +somthing like "my-file.rkt".</p></blockquote></blockquote></blockquote><blockquote class="SCodeFlow"><table cellspacing="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#(def._((quote._~23~25kernel)._syntax-source))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-line))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-column))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span> +converts it completely into an S-expression:</p><blockquote class="SCodeFlow"><table cellspacing="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#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-e))" class="RktValLink" 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" 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#(def._((quote._~23~25kernel)._syntax-e))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-e))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" pltdoc="x">syntax->list</a></span> gives the same result as +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-e))" class="RktValLink" pltdoc="x">syntax-e</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="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#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-e))" class="RktValLink" pltdoc="x">syntax-e</a></span> and <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" 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><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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#(def._((lib._racket%2Fprivate%2Flist..rkt)._reverse))" class="RktValLink" 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#(def._((quote._~23~25kernel)._cdr))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" 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#(def._((quote._~23~25kernel)._values))" class="RktValLink" 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><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#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span>. This converts the syntax into a plain old +list:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" 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#(def._((quote._~23~25kernel)._values))" class="RktValLink" 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#(def._((quote._~23~25kernel)._cdr))" class="RktValLink" 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#(def._((quote._~23~25kernel)._values))" class="RktValLink" 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#(def._((lib._racket%2Fprivate%2Flist..rkt)._reverse))" class="RktValLink" 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#(def._((quote._~23~25kernel)._values))" class="RktValLink" 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" 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#(def._((lib._racket%2Fprivate%2Flist..rkt)._reverse))" class="RktValLink" 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#(def._((quote._~23~25kernel)._cdr))" class="RktValLink" 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#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" pltdoc="x">syntax</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="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#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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" 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#(def._((quote._~23~25kernel)._values))" class="RktValLink" 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" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._make-pipe))" class="RktValLink" 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#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" pltdoc="x">#'</a></span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/void.html#(def._((quote._~23~25kernel)._void))" class="RktValLink" 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#(form._((quote._~23~25kernel)._if))" class="RktStxLink" pltdoc="x">if</a></span>:</p><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((quote._~23~25kernel)._if))" class="RktStxLink" 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#(form._((quote._~23~25kernel)._if))" class="RktStxLink" 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" class="RktBlk"><tr><td><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._cond))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._else))" class="RktStxLink" 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" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace"> </span><span class="RktVal">#t</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">"true"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>That seems to work. However, how about this:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((lib._racket%2Fprivate%2Fmisc..rkt)._displayln))" class="RktValLink" pltdoc="x">displayln</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if</span><span class="hspace"> </span><span class="RktVal">#t</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><table cellspacing="0"><tr><td><p><span class="RktOut">true</span></p></td></tr><tr><td><p><span class="RktOut">false</span></p></td></tr></table></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>One answer is that functional programming is good, and +side-effects are bad. But avoiding side-effects isn’t always +practical.</p></blockquote></blockquote></blockquote><p>Oops. Because the expressions have a side-effect, it’s obvious that +they are both evaluated. And that could be a problem—<wbr></wbr>what if the +side-effect includes deleting a file on disk? You wouldn’t want +<span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((quote._~23~25kernel)._if))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._delete-file))" class="RktValLink" 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#(def._((quote._~23~25kernel)._void))" class="RktValLink" 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" class="RktBlk"><tr><td><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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#(def._((quote._~23~25kernel)._cadr))" class="RktValLink" 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#(def._((quote._~23~25kernel)._caddr))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cadddr))" class="RktValLink" 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" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktVal">#t</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktOut">true</span></p></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-v2</span><span class="hspace"> </span><span class="RktVal">#f</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">display-and-return</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktOut">false</span></p></td></tr><tr><td><p><span class="RktRes">"false"</span></p></td></tr></table></blockquote><p>That gave the right answer. But how? Let’s pull out the transformer +function itself, and see what it did. We start with an example of some +input syntax:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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#(def._((lib._racket%2Fprivate%2Fmisc..rkt)._displayln))" class="RktValLink" 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#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span> to +change it into a plain Racket <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._list))" class="RktValLink" pltdoc="x">list</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</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#(def._((lib._racket%2Fprivate%2Fmisc..rkt)._displayln))" class="RktValLink" 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">(our-if-v2 #t true 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#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._cond))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._cadr))" class="RktValLink" pltdoc="x">cadr</a></span>, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._caddr))" class="RktValLink" pltdoc="x">caddr</a></span>, +and <span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cadddr))" class="RktValLink" pltdoc="x">cadddr</a></span> and arrange them into a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._cond))" class="RktStxLink" pltdoc="x">cond</a></span> form:</p><blockquote class="SCodeFlow"><table cellspacing="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#(def._((quote._~23~25kernel)._cadr))" class="RktValLink" 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#(def._((quote._~23~25kernel)._caddr))" class="RktValLink" 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#(def._((quote._~23~25kernel)._cadddr))" class="RktValLink" 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#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" pltdoc="x">syntax</a></span> using +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" pltdoc="x">datum->syntax</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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#(def._((quote._~23~25kernel)._cadr))" class="RktValLink" 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#(def._((quote._~23~25kernel)._caddr))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cadddr))" class="RktValLink" 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#(def._((quote._~23~25kernel)._cadddr))" class="RktValLink" 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#(form._((lib._racket%2Fmatch..rkt)._match))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._car))" class="RktValLink" 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" class="RktBlk"><tr><td><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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#(def._((quote._~23~25kernel)._cadr))" class="RktValLink" 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#(def._((quote._~23~25kernel)._caddr))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cadddr))" class="RktValLink" 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" class="RktBlk"><tr><td><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#(form._((lib._racket%2Fmatch..rkt)._match))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></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#(def._((quote._~23~25kernel)._list))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">false-expr</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr></table></blockquote><p>Great. Now let’s try using it:</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fmatch..rkt)._match))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span> form of <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" 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" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" 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" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#(form._((lib._racket%2Fmatch..rkt)._match))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></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#(def._((quote._~23~25kernel)._list))" class="RktValLink" pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktVal">[</span><span class="RktVal">else</span><span class="hspace"> </span><span class="RktRdr">,</span><span class="RktSym">false-expr</span><span class="RktVal">]</span><span class="RktVal">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-match-v2</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>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#(form._((quote._~23~25kernel)._begin-for-syntax))" class="RktStxLink" pltdoc="x">begin-for-syntax</a></span></h4><p>We used <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span> to <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fmatch..rkt)._match))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" pltdoc="x">require</a></span> it using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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#(form._((quote._~23~25kernel)._begin-for-syntax))" class="RktStxLink" pltdoc="x">begin-for-syntax</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/begin.html#(form._((quote._~23~25kernel)._begin-for-syntax))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-for-syntax))" class="RktStxLink" pltdoc="x">define-for-syntax</a></span>, which +composes <span class="RktSym"><a href="http://docs.racket-lang.org/reference/begin.html#(form._((quote._~23~25kernel)._begin-for-syntax))" class="RktStxLink" pltdoc="x">begin-for-syntax</a></span> and <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-for-syntax))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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#(form._((quote._~23~25kernel)._if))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" 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#(form._((quote._~23~25kernel)._begin-for-syntax))" class="RktStxLink" 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"> </span><span class="navright"><a href="Our_plan_of_attack.html" title="backward to "2 Our plan of attack"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="pattern-matching.html" title="forward to "4 Pattern matching: syntax-case and syntax-rules"" pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file diff --git a/What_s_the_point_of_splicing-let_.html b/What_s_the_point_of_splicing-let_.html @@ -0,0 +1,11 @@ +<!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>6 What's the point of splicing-let?</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" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" pltdoc="x">Fear of Macros</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="Preface.html" class="tocviewlink" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="Transform_.html" class="tocviewlink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="Syntax_parameters.html" class="tocviewlink" pltdoc="x">Syntax parameters</a></td></tr><tr><td align="right">6 </td><td><a href="" class="tocviewselflink" 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" 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" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" pltdoc="x">Epilogue</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"> </span><span class="navright"><a href="Syntax_parameters.html" title="backward to "5 Syntax parameters"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Robust_macros__syntax-parse.html" title="forward to "7 Robust macros: syntax-parse"" pltdoc="x">next →</a></span> </div><h3>6<tt> </tt><a name="(part._.What_s_the_point_of_splicing-let_)"></a>What’s the point of <span class="RktSym"><a href="http://docs.racket-lang.org/reference/splicing.html#(form._((lib._racket%2Fsplicing..rkt)._splicing-let))" class="RktStxLink" pltdoc="x">splicing-let</a></span>?</h3><p>I stared at <span class="RktSym">racket/splicing</span> for the longest time. What does +it do? Why would I use it? Why is it in the Macros section of the +reference?</p><p>Step one, <span class="strike">cut a hole in the box</span> +de-mythologize it. For example, using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/splicing.html#(form._((lib._racket%2Fsplicing..rkt)._splicing-let))" class="RktStxLink" pltdoc="x">splicing-let</a></span> like this:</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" pltdoc="x">require</a></span><span class="hspace"> </span><span class="RktSym">racket/splicing</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/splicing.html#(form._((lib._racket%2Fsplicing..rkt)._splicing-let))" class="RktStxLink" pltdoc="x">splicing-let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">get-x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">get-x is visible out here:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">get-x</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">0</span></p></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">but x is not:</span></td></tr><tr><td><span class="stt">> </span><span class="RktSym">x</span></td></tr><tr><td><p><span class="RktErr">x: undefined;</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">cannot reference an identifier before its definition</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in module: 'program</span></p></td></tr></table></blockquote><p>is equivalent to:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">get-y</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">y</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">get-y is visible out here:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">get-y</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">0</span></p></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">but y is not:</span></td></tr><tr><td><span class="stt">> </span><span class="RktSym">y</span></td></tr><tr><td><p><span class="RktErr">y: undefined;</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">cannot reference an identifier before its definition</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in module: 'program</span></p></td></tr></table></blockquote><p>This is the classic Lisp/Scheme/Racket idiom sometimes called "let +over lambda". <span class="refelem"><span class="refcolumn"><span class="refcontent">A +<a href="http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html">koan</a> +about closures and objects.</span></span></span> A closure hides <span class="RktSym">y</span>, which can +only be accessed via <span class="RktSym">get-y</span>.</p><p>So why would we care about the splicing forms? They can be more +concise, especially when there are multiple body forms:</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" pltdoc="x">require</a></span><span class="hspace"> </span><span class="RktSym">racket/splicing</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/splicing.html#(form._((lib._racket%2Fsplicing..rkt)._splicing-let))" class="RktStxLink" pltdoc="x">splicing-let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">inc</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/set_.html#(form._((quote._~23~25kernel)._set!))" class="RktStxLink" pltdoc="x">set!</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/generic-numbers.html#(def._((quote._~23~25kernel)._%2B))" class="RktValLink" pltdoc="x">+</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktVal">1</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">dec</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/set_.html#(form._((quote._~23~25kernel)._set!))" class="RktStxLink" pltdoc="x">set!</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/generic-numbers.html#(def._((quote._~23~25kernel)._-))" class="RktValLink" pltdoc="x"><span class="nobreak">-</span></a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktVal">1</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">get</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr></table></blockquote><p>The splicing variation is more convenient than the usual way:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((quote._~23~25kernel)._define-values))" class="RktStxLink" pltdoc="x">define-values</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">inc</span><span class="hspace"> </span><span class="RktSym">dec</span><span class="hspace"> </span><span class="RktSym">get</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/values.html#(def._((quote._~23~25kernel)._values))" class="RktValLink" pltdoc="x">values</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">inc</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/set_.html#(form._((quote._~23~25kernel)._set!))" class="RktStxLink" pltdoc="x">set!</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/generic-numbers.html#(def._((quote._~23~25kernel)._%2B))" class="RktValLink" pltdoc="x">+</a></span><span class="hspace"> </span><span class="RktVal">1</span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">dec</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/set_.html#(form._((quote._~23~25kernel)._set!))" class="RktStxLink" pltdoc="x">set!</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/generic-numbers.html#(def._((quote._~23~25kernel)._-))" class="RktValLink" pltdoc="x"><span class="nobreak">-</span></a></span><span class="hspace"> </span><span class="RktVal">1</span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">get</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr></table></blockquote><p>When there are many body forms—<wbr></wbr>and we’re generating them in a +macro—<wbr></wbr>the splicing variations can be much easier.</p><div class="navsetbottom"><span class="navleft"> </span><span class="navright"><a href="Syntax_parameters.html" title="backward to "5 Syntax parameters"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Robust_macros__syntax-parse.html" title="forward to "7 Robust macros: syntax-parse"" pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file diff --git a/index.html b/index.html @@ -0,0 +1,3 @@ +<!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" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="" class="tocviewselflink" pltdoc="x">Fear of Macros</a></td></tr></table></div><div class="tocviewsublistonly" style="display: block;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="Preface.html" class="tocviewlink" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="Transform_.html" class="tocviewlink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="pattern-matching.html" class="tocviewlink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr><tr><td align="right">5 </td><td><a href="Syntax_parameters.html" class="tocviewlink" 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" 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" 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" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" pltdoc="x">Epilogue</a></td></tr></table></div></div></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"> </span><span class="navright"><span class="nonavigation">← prev</span> <span class="nonavigation">up</span> <a href="Preface.html" title="forward to "1 Preface"" pltdoc="x">next →</a></span> </div><h2><a name="(part._.Fear_of_.Macros)"></a>Fear of Macros</h2><div class="SAuthorListBox"><span class="SAuthorList"><p class="author"><a href="http://www.greghendershott.com">Greg Hendershott</a></p></span></div><p><div class="SIntrapara"></div><div class="SIntrapara"><img src="fear-of-macros.jpg" alt="" /> +</div><div class="SIntrapara"><span class="Smaller">Copyright (c) 2012 by Greg Hendershott. All rights reserved.</span></div><div class="SIntrapara"><span class="Smaller">Last updated 2012-11-13 13:54:25</span></div><div class="SIntrapara">Feedback and corrections are <a href="https://github.com/greghendershott/fear-of-macros/issues">welcome here</a>.</div></p><p>Contents:</p><table cellspacing="0"><tr><td><p><span class="hspace"> </span><a href="Preface.html" class="toptoclink" pltdoc="x">1<span class="hspace"> </span>Preface</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Our_plan_of_attack.html" class="toptoclink" pltdoc="x">2<span class="hspace"> </span>Our plan of attack</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Transform_.html" class="toptoclink" pltdoc="x">3<span class="hspace"> </span>Transform!</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Transform_.html#(part._.What_is_a_syntax_transformer_)" class="toclink" pltdoc="x">3.1<span class="hspace"> </span>What is a syntax transformer?</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Transform_.html#(part._.What_s_the_input_)" class="toclink" pltdoc="x">3.2<span class="hspace"> </span>What’s the input?</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Transform_.html#(part._.Actually_transforming_the_input)" class="toclink" pltdoc="x">3.3<span class="hspace"> </span>Actually transforming the input</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Transform_.html#(part._.Compile_time_vs__run_time)" class="toclink" pltdoc="x">3.4<span class="hspace"> </span>Compile time vs. run time</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Transform_.html#(part._begin-for-syntax)" class="toclink" pltdoc="x">3.5<span class="hspace"> </span><span class="RktSym"><span class="RktStxLink">begin-for-syntax</span></span></a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="pattern-matching.html" class="toptoclink" pltdoc="x">4<span class="hspace"> </span>Pattern matching: syntax-case and syntax-rules</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="pattern-matching.html#(part._.Pattern_variable_vs__template---fight_)" class="toclink" pltdoc="x">4.1<span class="hspace"> </span>Pattern variable vs. template—<wbr></wbr>fight!</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="pattern-matching.html#(part._with-syntax)" class="toclink" pltdoc="x">4.1.1<span class="hspace"> </span><span class="RktSym"><span class="RktStxLink">with-syntax</span></span></a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="pattern-matching.html#(part._with-syntax_)" class="toclink" pltdoc="x">4.1.2<span class="hspace"> </span><span class="RktSym"><span class="RktStxLink">with-syntax*</span></span></a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="pattern-matching.html#(part._format-id)" class="toclink" pltdoc="x">4.1.3<span class="hspace"> </span><span class="RktSym"><span class="RktValLink">format-id</span></span></a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="pattern-matching.html#(part._.Another_example)" class="toclink" pltdoc="x">4.1.4<span class="hspace"> </span>Another example</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="pattern-matching.html#(part._.Making_our_own_struct)" class="toclink" pltdoc="x">4.2<span class="hspace"> </span>Making our own <span class="RktSym"><span class="RktStxLink">struct</span></span></a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="pattern-matching.html#(part._hash..refs)" class="toclink" pltdoc="x">4.3<span class="hspace"> </span>Using dot notation for nested hash lookups</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Syntax_parameters.html" class="toptoclink" pltdoc="x">5<span class="hspace"> </span>Syntax parameters</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="What_s_the_point_of_splicing-let_.html" class="toptoclink" pltdoc="x">6<span class="hspace"> </span>What’s the point of <span class="RktSym"><span class="RktStxLink">splicing-let</span></span>?</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Robust_macros__syntax-parse.html" class="toptoclink" pltdoc="x">7<span class="hspace"> </span>Robust macros: syntax-parse</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Robust_macros__syntax-parse.html#(part._.Error-handling_strategies_for_functions)" class="toclink" pltdoc="x">7.1<span class="hspace"> </span>Error-handling strategies for functions</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Robust_macros__syntax-parse.html#(part._.Error-handling_strategies_for_macros)" class="toclink" pltdoc="x">7.2<span class="hspace"> </span>Error-handling strategies for macros</a></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Robust_macros__syntax-parse.html#(part._.Using_syntax_parse)" class="toclink" pltdoc="x">7.3<span class="hspace"> </span>Using <span class="RktSym">syntax/parse</span></a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="References_and_Acknowledgments.html" class="toptoclink" pltdoc="x">8<span class="hspace"> </span>References and Acknowledgments</a></p></td></tr><tr><td><p><span class="hspace"></span></p></td></tr><tr><td><p><span class="hspace"> </span><a href="Epilogue.html" class="toptoclink" pltdoc="x">9<span class="hspace"> </span>Epilogue</a></p></td></tr></table><div class="navsetbottom"><span class="navleft"> </span><span class="navright"><span class="nonavigation">← prev</span> <span class="nonavigation">up</span> <a href="Preface.html" title="forward to "1 Preface"" pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file diff --git a/pattern-matching.html b/pattern-matching.html @@ -0,0 +1,121 @@ +<!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>4 Pattern matching: syntax-case and syntax-rules</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" /><link rel="stylesheet" type="text/css" href="gh.css" title="default" /><script type="text/javascript" src="scribble-common.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" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">▼</a></td><td></td><td><a href="index.html" class="tocviewlink" 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" pltdoc="x">Preface</a></td></tr><tr><td align="right">2 </td><td><a href="Our_plan_of_attack.html" class="tocviewlink" pltdoc="x">Our plan of attack</a></td></tr><tr><td align="right">3 </td><td><a href="Transform_.html" class="tocviewlink" pltdoc="x">Transform!</a></td></tr><tr><td align="right">4 </td><td><a href="" class="tocviewselflink" 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" 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" 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" 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" pltdoc="x">References and Acknowledgments</a></td></tr><tr><td align="right">9 </td><td><a href="Epilogue.html" class="tocviewlink" 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>4 </td><td><a href="" class="tocviewselflink" pltdoc="x">Pattern matching:<span class="mywbr"> </span> syntax-<wbr></wbr>case and syntax-<wbr></wbr>rules</a></td></tr></table><div class="tocviewsublistbottom" style="display: none;" id="tocview_1"><table cellspacing="0" cellpadding="0"><tr><td align="right">4.1 </td><td><a href="#(part._.Pattern_variable_vs__template---fight_)" class="tocviewlink" pltdoc="x">Pattern variable vs. template—<wbr></wbr>fight!</a></td></tr><tr><td align="right">4.2 </td><td><a href="#(part._.Making_our_own_struct)" class="tocviewlink" pltdoc="x">Making our own <span class="RktSym"><span class="RktStxLink">struct</span></span></a></td></tr><tr><td align="right">4.3 </td><td><a href="#(part._hash..refs)" class="tocviewlink" pltdoc="x">Using dot notation for nested hash lookups</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">4.1<tt> </tt></span><a href="#(part._.Pattern_variable_vs__template---fight_)" class="tocsubseclink" pltdoc="x">Pattern variable vs. template—<wbr></wbr>fight!</a></td></tr><tr><td><span class="tocsublinknumber">4.1.1<tt> </tt></span><a href="#(part._with-syntax)" class="tocsubseclink" pltdoc="x"><span class="RktSym"><span class="RktStxLink">with-<wbr></wbr>syntax</span></span></a></td></tr><tr><td><span class="tocsublinknumber">4.1.2<tt> </tt></span><a href="#(part._with-syntax_)" class="tocsubseclink" pltdoc="x"><span class="RktSym"><span class="RktStxLink">with-<wbr></wbr>syntax*</span></span></a></td></tr><tr><td><span class="tocsublinknumber">4.1.3<tt> </tt></span><a href="#(part._format-id)" class="tocsubseclink" pltdoc="x"><span class="RktSym"><span class="RktValLink">format-<wbr></wbr>id</span></span></a></td></tr><tr><td><span class="tocsublinknumber">4.1.4<tt> </tt></span><a href="#(part._.Another_example)" class="tocsubseclink" pltdoc="x">Another example</a></td></tr><tr><td><span class="tocsublinknumber">4.2<tt> </tt></span><a href="#(part._.Making_our_own_struct)" class="tocsubseclink" pltdoc="x">Making our own <span class="RktSym"><span class="RktStxLink">struct</span></span></a></td></tr><tr><td><span class="tocsublinknumber">4.3<tt> </tt></span><a href="#(part._hash..refs)" class="tocsubseclink" pltdoc="x">Using dot notation for nested hash lookups</a></td></tr></table></div></div><div class="maincolumn"><div class="main"><div class="navsettop"><span class="navleft"> </span><span class="navright"><a href="Transform_.html" title="backward to "3 Transform!"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Syntax_parameters.html" title="forward to "5 Syntax parameters"" pltdoc="x">next →</a></span> </div><h3>4<tt> </tt><a name="(part._pattern-matching)"></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"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cadddr))" class="RktValLink" pltdoc="x">cadddr</a></span>. It’s more convenient and less error-prone to use +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#(form._((lib._racket%2Fmatch..rkt)._match))" class="RktStxLink" pltdoc="x">match</a></span> to do pattern-matching.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Historically, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span> and +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-rules))" class="RktStxLink" pltdoc="x">syntax-rules</a></span> pattern matching came first. <span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#(form._((lib._racket%2Fmatch..rkt)._match))" class="RktStxLink" pltdoc="x">match</a></span> was +added to Racket later.</p></blockquote></blockquote></blockquote><p>It turns out that pattern-matching was one of the first improvements +to be added to the Racket macro system. It’s called +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span>, and has a shorthand for simple situations called +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></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"><a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" 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><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" 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="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/match.html#(form._((lib._racket%2Fmatch..rkt)._match))" class="RktStxLink" 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#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" 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="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._list))" class="RktValLink" pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" 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="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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="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></blockquote><p>Here’s what it looks like using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-case</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></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#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._cond))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._else))" class="RktStxLink" 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><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-case</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>Pretty similar, huh? The pattern matching part looks almost exactly +the same. The way we specify the new syntax is simpler. We don’t need +to do quasi-quoting and unquoting. We don’t need to use +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" pltdoc="x">datum->syntax</a></span>. Instead, we 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"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span>. It’s called <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-rule</span><span class="hspace"> </span><span class="RktSym">condition</span><span class="hspace"> </span><span class="RktSym">true-expr</span><span class="hspace"> </span><span class="RktSym">false-expr</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._cond))" class="RktStxLink" 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="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._else))" class="RktStxLink" 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><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-if-using-syntax-rule</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="hspace"> </span><span class="RktVal">"true"</span><span class="hspace"> </span><span class="RktVal">"false"</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"true"</span></p></td></tr></table></blockquote><p>Here’s the thing about <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></span>. Because it’s so +simple, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></span> is often the first thing people are +taught about macros. But it’s almost deceptively simple. It looks so +much like defining a normal run time function—<wbr></wbr>yet it’s not. It’s +working at compile time, not run time. Worse, the moment you want to +do more than <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></span> can handle, you can fall off +a cliff into what feels like complicated and confusing +territory. Hopefully, because we started with a basic syntax +transformer, and worked up from that, we won’t have that problem. We +can appreciate <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fmisc..rkt)._define-syntax-rule))" class="RktStxLink" pltdoc="x">define-syntax-rule</a></span> as a convenient shorthand, +but not be scared of, or confused about, that for which it’s +shorthand.</p><p>Most of the materials I found for learning macros, including the +Racket <span style="font-style: italic">Guide</span>, do a very good job explaining +<a href="http://docs.racket-lang.org/guide/pattern-macros.html">how +patterns and templates work</a>. So I won’t regurgitate that here.</p><p>Sometimes, we need to go a step beyond the pattern and template. Let’s +look at some examples, how we can get confused, and how to get it +working.</p><h4>4.1<tt> </tt><a name="(part._.Pattern_variable_vs__template---fight_)"></a>Pattern variable vs. template—<wbr></wbr>fight!</h4><p>Let’s say we want to define a function with a hyphenated name, a-b, +but we supply the a and b parts separately. The Racket <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define-struct.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._struct))" class="RktStxLink" pltdoc="x">struct</a></span> +macro does something like this: <span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define-struct.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._struct))" class="RktStxLink" pltdoc="x">struct</a></span><span class="stt"> </span><span class="RktSym">foo</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">field1</span><span class="stt"> </span><span class="RktSym">field2</span><span class="RktPn">)</span><span class="RktPn">)</span> +automatically defines a number of functions whose names are variations +on the name <span class="RktSym">foo</span>—<wbr></wbr>such as <span class="RktSym">foo-field1</span>, +<span class="RktSym">foo-field2</span>, <span class="RktSym">foo?</span>, and so on.</p><p>So let’s pretend we’re doing something like that. We want to transform +the syntax <span class="RktPn">(</span><span class="RktSym">hyphen-define</span><span class="stt"> </span><span class="RktSym">a</span><span class="stt"> </span><span class="RktSym">b</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktSym">body</span><span class="RktPn">)</span> to the syntax +<span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">a-b</span><span class="stt"> </span><span class="RktSym">args</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktSym">body</span><span class="RktPn">)</span>.</p><p>A wrong first attempt is:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong1</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._string-~3esymbol))" class="RktValLink" pltdoc="x">string->symbol</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._format))" class="RktValLink" pltdoc="x">format</a></span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktErr">eval:47:0: a: pattern variable cannot be used outside of a</span></p></td></tr><tr><td><p><span class="RktErr">template</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: a</span></p></td></tr></table></blockquote><p>Huh. We have no idea what this error message means. Well, let’s try to +work it out. The "template" the error message refers to is the +<span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></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"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></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"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span> portion. The +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span> isn’t part of that template. It sounds like we can’t use +<span class="RktSym">a</span> (or <span class="RktSym">b</span>) in the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span> part.</p><p>In fact, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span> can have as many templates as you +want. The obvious, required template is the final expression supplying +the output syntax. But you can use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" pltdoc="x">syntax</a></span> (a.k.a. #’) on a +pattern variable. This makes another template, albeit a small, "fun +size" template. Let’s try that:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong1.1</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._string-~3esymbol))" class="RktValLink" pltdoc="x">string->symbol</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._format))" class="RktValLink" pltdoc="x">format</a></span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></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></table></blockquote><p>No more error—<wbr></wbr>good! Let’s try to use it:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong1.1</span><span class="hspace"> </span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">bar</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">foo-bar</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">foo-bar: undefined;</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">cannot reference an identifier before its definition</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in module: 'program</span></p></td></tr></table></blockquote><p>Apparently our macro is defining a function with some name other than +<span class="RktSym">foo-bar</span>. Huh.</p><p><div class="SIntrapara">This is where the Macro Stepper in DrRacket is +invaluable. </div><div class="SIntrapara"><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Even if you prefer mostly to use Emacs, this +is a situation where it’s definitely worth temporarily using DrRacket +for its Macro Stepper.</p></blockquote></blockquote></blockquote></div></p><p><img src="macro-stepper.png" alt="" width="598" height="564" /></p><p>The Macro Stepper says that the use of our macro:</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong1.1</span><span class="hspace"> </span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">bar</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></p></blockquote><p>expanded to:</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></p></blockquote><p>Well that explains it. Instead, we wanted to expand to:</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo-bar</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></p></blockquote><p>Our template is using the symbol <span class="RktSym">name</span> but we wanted its +value, such as <span class="RktSym">foo-bar</span> in this use of our macro.</p><p>Is there anything we already know that behaves like this—<wbr></wbr>where using +a variable in the template yields its value? Yes: Pattern +variables. Our pattern doesn’t include <span class="RktSym">name</span> because we don’t +expect it in the original syntax—<wbr></wbr>indeed the whole point of this +macro is to create it. So <span class="RktSym">name</span> can’t be in the main +pattern. Fine—<wbr></wbr>let’s make an <span style="font-style: italic">additional</span> pattern. We can do +that using an additional, nested <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong1.2</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._string-~3esymbol))" class="RktValLink" pltdoc="x">string->symbol</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._format))" class="RktValLink" pltdoc="x">format</a></span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></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></table></blockquote><p>Looks weird? Let’s take a deep breath. Normally our transformer +function is given syntax by Racket, and we pass that syntax to +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span>. But we can also create some syntax of our own, +on the fly, and pass <span style="font-style: italic">that</span> to <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span>. That’s all +we’re doing here. The whole <span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" pltdoc="x">datum->syntax</a></span><span class="stt"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span> expression is +syntax that we’re creating on the fly. We can give that to +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span>, and match it using a pattern variable named +<span class="RktSym">name</span>. Voila, we have a new pattern variable. We can use it in +a template, and its value will go in the template.</p><p>We might have one more—<wbr></wbr>just one, I promise!—<wbr></wbr>small problem left. +Let’s try to use our new version:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/wrong1.2</span><span class="hspace"> </span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">bar</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">foo-bar</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">foo-bar: undefined;</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">cannot reference an identifier before its definition</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in module: 'program</span></p></td></tr></table></blockquote><p>Hmm. <span class="RktSym">foo-bar</span> is <span style="font-style: italic">still</span> not defined. Back to the Macro +Stepper. It says now we’re expanding to:</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">|#<syntax:11:24foo>-#<syntax:11:28 bar>|</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></p></blockquote><p>Oh right: <span class="RktRdr">#'</span><span class="RktSym">a</span> and <span class="RktRdr">#'</span><span class="RktSym">b</span> are syntax objects. Therefore</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._string-~3esymbol))" class="RktValLink" pltdoc="x">string->symbol</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._format))" class="RktValLink" pltdoc="x">format</a></span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span></p></blockquote><p>is the printed form of both syntax objects, joined by a hyphen:</p><blockquote class="SCodeFlow"><p><span class="RktSym">|#<syntax:11:24foo>-#<syntax:11:28 bar>|</span></p></blockquote><p>Instead we want the datum in the syntax objects, such as the symbols +<span class="RktSym">foo</span> and <span class="RktSym">bar</span>. Which we get using +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok1</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._string-~3esymbol))" class="RktValLink" pltdoc="x">string->symbol</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._format))" class="RktValLink" pltdoc="x">format</a></span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok1</span><span class="hspace"> </span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">bar</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">foo-bar</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#t</span></p></td></tr></table></blockquote><p>And now it works!</p><p>Next, some shortcuts.</p><h5>4.1.1<tt> </tt><a name="(part._with-syntax)"></a><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span></h5><p>Instead of an additional, nested <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span>, we could use +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="refelem"><span class="refcolumn"><span class="refcontent">Another name for +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span> could be, "with new pattern variable".</span></span></span>. This +rearranges the <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span> to look more like a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span> +statement—<wbr></wbr>first the name, then the value. Also it’s more convenient +if we need to define more than one pattern variable.</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok2</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._string-~3esymbol))" class="RktValLink" pltdoc="x">string->symbol</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._format))" class="RktValLink" pltdoc="x">format</a></span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok2</span><span class="hspace"> </span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">bar</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">foo-bar</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#t</span></p></td></tr></table></blockquote><p>Again, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span> is simply <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span> rearranged:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span style="font-style: italic"><syntax></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">[</span><span style="font-weight: bold"><pattern></span><span class="hspace"> </span><span class="RktSym"><body></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/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span style="font-weight: bold"><pattern></span><span class="hspace"> </span><span style="font-style: italic"><syntax></span><span class="RktPn">]</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym"><body></span><span class="RktPn">)</span></td></tr></table></blockquote><p>Whether you use an additional <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span> or use +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span>, either way you are simply defining additional +pattern variables. Don’t let the terminology and structure make it +seem mysterious.</p><h5>4.1.2<tt> </tt><a name="(part._with-syntax_)"></a><span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(form._((lib._racket%2Fsyntax..rkt)._with-syntax*))" class="RktStxLink" pltdoc="x">with-syntax*</a></span></h5><p>We know that <span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span> doesn’t let us use a binding in a subsequent +one:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktSym">a</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">b</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktErr">a: undefined;</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">cannot reference an identifier before its definition</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in module: 'program</span></p></td></tr></table></blockquote><p>Instead we can nest <span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span>s:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktSym">a</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktRes">0</span></p></td></tr></table></blockquote><p>Or use a shorthand for nesting, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let*))" class="RktStxLink" pltdoc="x">let*</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let*))" class="RktStxLink" pltdoc="x">let*</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktSym">a</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">b</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><p><span class="RktRes">0</span></p></td></tr></table></blockquote><p>Similarly, instead of writing nested <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span>s, we can use +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(form._((lib._racket%2Fsyntax..rkt)._with-syntax*))" class="RktStxLink" pltdoc="x">with-syntax*</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span><span class="hspace"> </span><span class="RktSym">racket/syntax</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">a</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(form._((lib._racket%2Fsyntax..rkt)._with-syntax*))" class="RktStxLink" pltdoc="x">with-syntax*</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">c</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">c</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>One gotcha is that <span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(form._((lib._racket%2Fsyntax..rkt)._with-syntax*))" class="RktStxLink" pltdoc="x">with-syntax*</a></span> isn’t provided by +<span class="RktSym">racket/base</span>. We must <span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span><span class="stt"> </span><span class="RktSym">racket/syntax</span><span class="RktPn">)</span><span class="RktPn">)</span>. Otherwise we may get a rather bewildering error +message:</p><p><span style="font-style: italic"><span class="stt">...: ellipses not allowed as an expression in: ...</span></span>.</p><h5>4.1.3<tt> </tt><a name="(part._format-id)"></a><span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span></h5><p>There is a utility function in <span class="RktSym">racket/syntax</span> called +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span> that lets us format identifier names more +succinctly than what we did above:</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span><span class="hspace"> </span><span class="RktSym">racket/syntax</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok3</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define/ok3</span><span class="hspace"> </span><span class="RktSym">bar</span><span class="hspace"> </span><span class="RktSym">baz</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">bar-baz</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#t</span></p></td></tr></table></blockquote><p>Using <span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span> is convenient as it handles the tedium of +converting from syntax to symbol datum to string ... and all the way +back.</p><h5>4.1.4<tt> </tt><a name="(part._.Another_example)"></a>Another example</h5><p>Finally, here’s a variation that accepts an arbitary number of name +parts to be joined with hyphens:</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span><span class="hspace"> </span><span class="RktSym">racket/string</span><span class="hspace"> </span><span class="RktSym">racket/syntax</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define*</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">names</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let*))" class="RktStxLink" pltdoc="x">let*</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">names/sym</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket%2Fprivate%2Fmap..rkt)._map))" class="RktValLink" pltdoc="x">map</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-e))" class="RktValLink" pltdoc="x">syntax-e</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">names</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">names/str</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket%2Fprivate%2Fmap..rkt)._map))" class="RktValLink" pltdoc="x">map</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._symbol-~3estring))" class="RktValLink" pltdoc="x">symbol->string</a></span><span class="hspace"> </span><span class="RktSym">names/sym</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">name/str</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/strings.html#(def._((lib._racket%2Fstring..rkt)._string-join))" class="RktValLink" pltdoc="x">string-join</a></span><span class="hspace"> </span><span class="RktSym">names/str</span><span class="hspace"> </span><span class="RktVal">"-"</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">name/sym</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._string-~3esymbol))" class="RktValLink" pltdoc="x">string->symbol</a></span><span class="hspace"> </span><span class="RktSym">name/str</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" pltdoc="x">datum->syntax</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktSym">name/sym</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#`</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktSym">args</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">body0</span><span class="hspace"> </span><span class="RktSym">body</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hyphen-define*</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktSym">bar</span><span class="hspace"> </span><span class="RktSym">baz</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">v</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._*))" class="RktValLink" pltdoc="x">*</a></span><span class="hspace"> </span><span class="RktVal">2</span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">foo-bar-baz</span><span class="hspace"> </span><span class="RktVal">50</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">100</span></p></td></tr></table></blockquote><p>To review:</p><ul><li><p>You can’t use a pattern variable outside of a template. But +you can use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax))" class="RktStxLink" pltdoc="x">syntax</a></span> or <span class="stt">#</span><span class="stt">’</span><span class="stt"></span> on a pattern variable to make +an ad hoc, "fun size" template.</p></li><li><p>If you want to munge pattern variables for use in the +template, <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span> is your friend, because it lets you +create new pattern variables.</p></li><li><p>Usually you’ll need to use <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span> to get the +interesting value inside.</p></li><li><p><span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span> is convenient for formatting identifier +names.</p></li></ul><h4>4.2<tt> </tt><a name="(part._.Making_our_own_struct)"></a>Making our own <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define-struct.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._struct))" class="RktStxLink" pltdoc="x">struct</a></span></h4><p>Let’s apply what we just learned to a more-realistic example. We’ll +pretend that Racket doesn’t already have a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/define-struct.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._struct))" class="RktStxLink" pltdoc="x">struct</a></span> +capability. Fortunately, we can write a macro to provide our own +system for defining and using structures. To keep things simple, our +structure will be immutable (read-only) and it won’t support +inheritance.</p><p>Given a structure declaration like:</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym">our-struct</span><span class="hspace"> </span><span class="RktSym">name</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">field1</span><span class="hspace"> </span><span class="RktSym">field2</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span></p></blockquote><p>We need to define some procedures:</p><ul><li><p>A constructor procedure whose name is the struct name. We’ll +represent structures as a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector))" class="RktValLink" pltdoc="x">vector</a></span>. The structure name will be +element zero. The fields will be elements one onward.</p></li><li><p>A predicate, whose name is the struct name with <span class="stt">?</span> +appended.</p></li><li><p>For each field, an accessor procedure to get its value. These +will be named struct-field (the name of the struct, a hyphen, and the +field name).</p></li></ul><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span><span class="hspace"> </span><span class="RktSym">racket/syntax</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-struct</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#(form._((lib._syntax%2Fparse..rkt)._id))" class="RktStxLink" pltdoc="x">id</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">fields</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">pred-id</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">"~a?"</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#(form._((lib._syntax%2Fparse..rkt)._id))" class="RktStxLink" pltdoc="x">id</a></span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#`</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/begin.html#(form._((quote._~23~25kernel)._begin))" class="RktStxLink" pltdoc="x">begin</a></span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Define a constructor.</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#(form._((lib._syntax%2Fparse..rkt)._id))" class="RktStxLink" pltdoc="x">id</a></span><span class="hspace"> </span><span class="RktSym">fields</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/procedures.html#(def._((lib._racket%2Fprivate%2Fbase..rkt)._apply))" class="RktValLink" pltdoc="x">apply</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector))" class="RktValLink" pltdoc="x">vector</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cons))" class="RktValLink" pltdoc="x">cons</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">id</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._list))" class="RktValLink" pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym">fields</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Define a predicate.</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">pred-id</span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._and))" class="RktStxLink" pltdoc="x">and</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector~3f))" class="RktValLink" pltdoc="x">vector?</a></span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._eq~3f))" class="RktValLink" pltdoc="x">eq?</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector-ref))" class="RktValLink" pltdoc="x">vector-ref</a></span><span class="hspace"> </span><span class="RktSym">v</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">id</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Define an accessor for each field.</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#,@</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/for.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for%2Flist))" class="RktStxLink" pltdoc="x">for/list</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</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/stxops.html#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">fields</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">n</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/sequences.html#(def._((lib._racket%2Fprivate%2Fbase..rkt)._in-naturals))" class="RktValLink" pltdoc="x">in-naturals</a></span><span class="hspace"> </span><span class="RktVal">1</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">acc-id</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#(form._((lib._syntax%2Fparse..rkt)._id))" class="RktStxLink" pltdoc="x">id</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">ix</span><span class="hspace"> </span><span class="RktSym">n</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#`</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">acc-id</span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/when_unless.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._unless))" class="RktStxLink" pltdoc="x">unless</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">pred-id</span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._error))" class="RktValLink" pltdoc="x">error</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">acc-id</span><span class="hspace"> </span><span class="RktVal">"~a is not a ~a struct"</span><span class="hspace"> </span><span class="RktSym">v</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">id</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector-ref))" class="RktValLink" pltdoc="x">vector-ref</a></span><span class="hspace"> </span><span class="RktSym">v</span><span class="hspace"> </span><span class="RktSym">ix</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="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Test it out</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" pltdoc="x">require</a></span><span class="hspace"> </span><span class="RktSym">rackunit</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-struct</span><span class="hspace"> </span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</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/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">s</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo</span><span class="hspace"> </span><span class="RktVal">1</span><span class="hspace"> </span><span class="RktVal">2</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">check-true</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo?</span><span class="hspace"> </span><span class="RktSym">s</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">check-false</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo?</span><span class="hspace"> </span><span class="RktVal">1</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">check-equal?</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo-a</span><span class="hspace"> </span><span class="RktSym">s</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">1</span><span class="RktPn">)</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">check-equal?</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo-b</span><span class="hspace"> </span><span class="RktSym">s</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">2</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">check-exn</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._exn~3afail~3f))" class="RktValLink" pltdoc="x">exn:fail?</a></span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">foo-a</span><span class="hspace"> </span><span class="RktVal">"furble"</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">The tests passed.</span></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Next, what if someone tries to declare:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-struct</span><span class="hspace"> </span><span class="RktVal">"blah"</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktVal">"blah"</span><span class="hspace"> </span><span class="RktVal">"blah"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">format-id: contract violation</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">expected: (or/c string? symbol? identifier? keyword? char?</span></p></td></tr><tr><td><p><span class="RktErr">number?)</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">given: #<syntax:83:0 "blah"></span></p></td></tr></table></blockquote><p>The error message is not very helpful. It’s coming from +<span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span>, which is a private implementation detail of our macro.</p><p>You may know that a <span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span> clause can take an +optional "guard" or "fender" expression. Instead of</p><blockquote class="SCodeFlow"><p><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/stxparse-specifying.html#(form._((lib._syntax%2Fparse..rkt)._pattern))" class="RktStxLink" pltdoc="x">pattern</a></span><span class="hspace"> </span><span class="RktSym">template</span><span class="RktPn">]</span></p></blockquote><p>It can be:</p><blockquote class="SCodeFlow"><p><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/stxparse-specifying.html#(form._((lib._syntax%2Fparse..rkt)._pattern))" class="RktStxLink" pltdoc="x">pattern</a></span><span class="hspace"> </span><span class="RktSym">guard</span><span class="hspace"> </span><span class="RktSym">template</span><span class="RktPn">]</span></p></blockquote><p>Let’s add a guard expression to our clause:</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span><span class="hspace"> </span><span class="RktSym">racket/syntax</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">our-struct</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#(form._((lib._syntax%2Fparse..rkt)._id))" class="RktStxLink" pltdoc="x">id</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">fields</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Guard or "fender" expression:</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket%2Fprivate%2Fmap..rkt)._for-each))" class="RktValLink" pltdoc="x">for-each</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/when_unless.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._unless))" class="RktStxLink" pltdoc="x">unless</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((lib._racket%2Fprivate%2Fstx..rkt)._identifier~3f))" class="RktValLink" pltdoc="x">identifier?</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._raise-syntax-error))" class="RktValLink" pltdoc="x">raise-syntax-error</a></span><span class="hspace"> </span><span class="RktVal">#f</span><span class="hspace"> </span><span class="RktVal">"not an identifier"</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cons))" class="RktValLink" pltdoc="x">cons</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#(form._((lib._syntax%2Fparse..rkt)._id))" class="RktStxLink" pltdoc="x">id</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">fields</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">pred-id</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">"~a?"</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#(form._((lib._syntax%2Fparse..rkt)._id))" class="RktStxLink" pltdoc="x">id</a></span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#`</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/begin.html#(form._((quote._~23~25kernel)._begin))" class="RktStxLink" pltdoc="x">begin</a></span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Define a constructor.</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#(form._((lib._syntax%2Fparse..rkt)._id))" class="RktStxLink" pltdoc="x">id</a></span><span class="hspace"> </span><span class="RktSym">fields</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/procedures.html#(def._((lib._racket%2Fprivate%2Fbase..rkt)._apply))" class="RktValLink" pltdoc="x">apply</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector))" class="RktValLink" pltdoc="x">vector</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cons))" class="RktValLink" pltdoc="x">cons</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">id</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._list))" class="RktValLink" pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym">fields</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Define a predicate.</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">pred-id</span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._and))" class="RktStxLink" pltdoc="x">and</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector~3f))" class="RktValLink" pltdoc="x">vector?</a></span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._eq~3f))" class="RktValLink" pltdoc="x">eq?</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector-ref))" class="RktValLink" pltdoc="x">vector-ref</a></span><span class="hspace"> </span><span class="RktSym">v</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">id</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Define an accessor for each field.</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#,@</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/for.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for%2Flist))" class="RktStxLink" pltdoc="x">for/list</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</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/stxops.html#(def._((quote._~23~25kernel)._syntax-~3elist))" class="RktValLink" pltdoc="x">syntax->list</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">fields</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._......))" class="RktStxLink" pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">n</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/sequences.html#(def._((lib._racket%2Fprivate%2Fbase..rkt)._in-naturals))" class="RktValLink" pltdoc="x">in-naturals</a></span><span class="hspace"> </span><span class="RktVal">1</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">acc-id</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/syntax-util.html#(def._((lib._racket%2Fsyntax..rkt)._format-id))" class="RktValLink" pltdoc="x">format-id</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktVal">"~a-~a"</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#(form._((lib._syntax%2Fparse..rkt)._id))" class="RktStxLink" pltdoc="x">id</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">ix</span><span class="hspace"> </span><span class="RktSym">n</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#`</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">acc-id</span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/when_unless.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._unless))" class="RktStxLink" pltdoc="x">unless</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">pred-id</span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._error))" class="RktValLink" pltdoc="x">error</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">acc-id</span><span class="hspace"> </span><span class="RktVal">"~a is not a ~a struct"</span><span class="hspace"> </span><span class="RktSym">v</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">id</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector-ref))" class="RktValLink" pltdoc="x">vector-ref</a></span><span class="hspace"> </span><span class="RktSym">v</span><span class="hspace"> </span><span class="RktSym">ix</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="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Now the same misuse gives a better error message:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">our-struct</span><span class="hspace"> </span><span class="RktVal">"blah"</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktVal">"blah"</span><span class="hspace"> </span><span class="RktVal">"blah"</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">eval:86:0: our-struct: not an identifier</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">at: "blah"</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: (our-struct "blah" ("blah" "blah"))</span></p></td></tr></table></blockquote><p>Later, we’ll see how <span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Parsing_Syntax.html#(form._((lib._syntax%2Fparse..rkt)._syntax-parse))" class="RktStxLink" pltdoc="x">syntax-parse</a></span> makes it even easier to +check usage and provide helpful messages about mistakes.</p><h4>4.3<tt> </tt><a name="(part._hash..refs)"></a>Using dot notation for nested hash lookups</h4><p>The previous two examples used a macro to define functions whose names +were made by joining identifiers provided to the macro. This example +does the opposite: The identifier given to the macro is split into +pieces.</p><p>If you write programs for web services you deal with JSON, which is +represented in Racket by a <span class="RktSym">jsexpr?</span>. JSON often has +dictionaries that contain other dictionaries. In a <span class="RktSym">jsexpr?</span> +these are represented by nested <span class="RktSym"><a href="http://docs.racket-lang.org/reference/hashtables.html#(def._((quote._~23~25kernel)._hasheq))" class="RktValLink" pltdoc="x">hasheq</a></span> tables:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Nested `hasheq</span><span class="RktCmt">'</span><span class="RktCmt">s typical of a jsexpr:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define))" class="RktStxLink" pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">js</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/hashtables.html#(def._((quote._~23~25kernel)._hasheq))" class="RktValLink" pltdoc="x">hasheq</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">a</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/hashtables.html#(def._((quote._~23~25kernel)._hasheq))" class="RktValLink" pltdoc="x">hasheq</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">b</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/hashtables.html#(def._((quote._~23~25kernel)._hasheq))" class="RktValLink" pltdoc="x">hasheq</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">c</span><span class="hspace"> </span><span class="RktVal">"value"</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>In JavaScript you can use dot notation:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktSym">foo</span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._~3d))" class="RktValLink" pltdoc="x">=</a></span><span class="RktMeta"></span><span class="hspace"> </span><span class="RktMeta"></span><span class="RktSym">js.a.b.c</span><span class="RktCmt">;</span><span class="RktMeta"></span></td></tr></table></blockquote><p>In Racket it’s not so convenient:</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/hashtables.html#(def._((quote._~23~25kernel)._hash-ref))" class="RktValLink" pltdoc="x">hash-ref</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/hashtables.html#(def._((quote._~23~25kernel)._hash-ref))" class="RktValLink" pltdoc="x">hash-ref</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/hashtables.html#(def._((quote._~23~25kernel)._hash-ref))" class="RktValLink" pltdoc="x">hash-ref</a></span><span class="hspace"> </span><span class="RktSym">js</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">a</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">b</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">c</span><span class="RktPn">)</span></p></blockquote><p>We can write a helper function to make this a bit cleaner:</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">This helper function:</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/attaching-contracts-to-values.html#(form._((lib._racket%2Fcontract%2Fregion..rkt)._define%2Fcontract))" class="RktStxLink" pltdoc="x">define/contract</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hash-refs</span><span class="hspace"> </span><span class="RktSym">h</span><span class="hspace"> </span><span class="RktSym">ks</span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">def</span><span class="hspace"> </span><span class="RktVal">#f</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/hashtables.html#(def._((quote._~23~25kernel)._hash~3f))" class="RktValLink" pltdoc="x">hash?</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/data-structure-contracts.html#(def._((lib._racket%2Fcontract%2Fprivate%2Fmisc..rkt)._listof))" class="RktValLink" pltdoc="x">listof</a></span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/data-structure-contracts.html#(def._((lib._racket%2Fcontract%2Fprivate%2Fmisc..rkt)._any%2Fc))" class="RktValLink" pltdoc="x">any/c</a></span><span class="RktPn">)</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/data-structure-contracts.html#(def._((lib._racket%2Fcontract%2Fprivate%2Fmisc..rkt)._any%2Fc))" class="RktValLink" pltdoc="x">any/c</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">. </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/function-contracts.html#(form._((lib._racket%2Fcontract%2Fbase..rkt)._-~3e*))" class="RktStxLink" pltdoc="x"><span class="nobreak">-></span>*</a></span><span class="RktPn"> .</span><span class="hspace"> </span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/data-structure-contracts.html#(form._((lib._racket%2Fcontract%2Fprivate%2Fmisc..rkt)._any))" class="RktStxLink" pltdoc="x">any</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(form._((lib._racket%2Fprivate%2Fmore-scheme..rkt)._with-handlers))" class="RktStxLink" pltdoc="x">with-handlers</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._exn~3afail~3f))" class="RktValLink" pltdoc="x">exn:fail?</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/procedures.html#(def._((lib._racket%2Ffunction..rkt)._const))" class="RktValLink" pltdoc="x">const</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._cond))" class="RktStxLink" pltdoc="x">cond</a></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/procedures.html#(def._((quote._~23~25kernel)._procedure~3f))" class="RktValLink" pltdoc="x">procedure?</a></span><span class="hspace"> </span><span class="RktSym">def</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">def</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._else))" class="RktStxLink" pltdoc="x">else</a></span><span class="hspace"> </span><span class="RktSym">def</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/for.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for%2Ffold))" class="RktStxLink" pltdoc="x">for/fold</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">h</span><span class="hspace"> </span><span class="RktSym">h</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">k</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/sequences.html#(def._((lib._racket%2Fprivate%2Fbase..rkt)._in-list))" class="RktValLink" pltdoc="x">in-list</a></span><span class="hspace"> </span><span class="RktSym">ks</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/hashtables.html#(def._((quote._~23~25kernel)._hash-ref))" class="RktValLink" pltdoc="x">hash-ref</a></span><span class="hspace"> </span><span class="RktSym">h</span><span class="hspace"> </span><span class="RktSym">k</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="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Lets us say:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hash-refs</span><span class="hspace"> </span><span class="RktSym">js</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">a</span><span class="hspace"> </span><span class="RktVal">b</span><span class="hspace"> </span><span class="RktVal">c</span><span class="RktVal">)</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"value"</span></p></td></tr></table></blockquote><p>That’s better. Can we go even further and use a dot notation somewhat +like JavaScript?</p><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">This macro:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/require.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span><span class="hspace"> </span><span class="RktSym">racket/syntax</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">If the optional `default</span><span class="RktCmt">'</span><span class="RktCmt"> is missing, assume it</span><span class="RktCmt">'</span><span class="RktCmt">s #f.</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">chain</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktSym">chain</span><span class="hspace"> </span><span class="RktVal">#f</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">chain</span><span class="hspace"> </span><span class="RktSym">default</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</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/pairs.html#(def._((lib._racket%2Fprivate%2Fmap..rkt)._map))" class="RktValLink" pltdoc="x">map</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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/symbols.html#(def._((quote._~23~25kernel)._string-~3esymbol))" class="RktValLink" pltdoc="x">string->symbol</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/regexp.html#(def._((lib._racket%2Fprivate%2Fbase..rkt)._regexp-split))" class="RktValLink" pltdoc="x">regexp-split</a></span><span class="hspace"> </span><span class="RktVal">#rx"\\."</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._symbol-~3estring))" class="RktValLink" pltdoc="x">symbol->string</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">chain</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">h</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._car))" class="RktValLink" pltdoc="x">car</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">ks</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cdr))" class="RktValLink" pltdoc="x">cdr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">hash-refs</span><span class="hspace"> </span><span class="RktSym">h</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">ks</span><span class="hspace"> </span><span class="RktSym">default</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="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Gives us "sugar" to say this:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktSym">js.a.b.c</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">"value"</span></p></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Try finding a key that doesn</span><span class="RktCmt">'</span><span class="RktCmt">t exist:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktSym">js.blah</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">#f</span></p></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Try finding a key that doesn</span><span class="RktCmt">'</span><span class="RktCmt">t exist, specifying the default:</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktSym">js.blah</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">did-not-exist</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktRes">'did-not-exist</span></p></td></tr></table></blockquote><p>It works!</p><p>We’ve started to appreciate that our macros should give helpful +messages when used in error. Let’s try to do that here.</p><blockquote class="SCodeFlow"><table cellspacing="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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._require))" class="RktStxLink" 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#(form._((lib._racket%2Fprivate%2Fbase..rkt)._for-syntax))" class="RktStxLink" pltdoc="x">for-syntax</a></span><span class="hspace"> </span><span class="RktSym">racket/syntax</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><table cellspacing="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._define-syntax))" class="RktStxLink" pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._syntax-case))" class="RktStxLink" pltdoc="x">syntax-case</a></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Check for no args at all</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._raise-syntax-error))" class="RktValLink" pltdoc="x">raise-syntax-error</a></span><span class="hspace"> </span><span class="RktVal">#f</span><span class="hspace"> </span><span class="RktVal">"Expected (hash.key0[.key1 ...] [default])"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">chain</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">chain</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktSym">chain</span><span class="hspace"> </span><span class="RktVal">#f</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt).__))" class="RktStxLink" pltdoc="x">_</a></span><span class="hspace"> </span><span class="RktSym">chain</span><span class="hspace"> </span><span class="RktSym">default</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Check that chain is a symbol, not e.g. a number or string</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/when_unless.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._unless))" class="RktStxLink" pltdoc="x">unless</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._symbol~3f))" class="RktValLink" pltdoc="x">symbol?</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-e))" class="RktValLink" pltdoc="x">syntax-e</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">chain</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._raise-syntax-error))" class="RktValLink" pltdoc="x">raise-syntax-error</a></span><span class="hspace"> </span><span class="RktVal">#f</span><span class="hspace"> </span><span class="RktVal">"Expected (hash.key0[.key1 ...] [default])"</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">chain</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/let.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._let))" class="RktStxLink" pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</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/pairs.html#(def._((lib._racket%2Fprivate%2Fmap..rkt)._map))" class="RktValLink" pltdoc="x">map</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/lambda.html#(form._((lib._racket%2Fprivate%2Fbase..rkt)._lambda))" class="RktStxLink" pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._datum-~3esyntax))" class="RktValLink" 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/symbols.html#(def._((quote._~23~25kernel)._string-~3esymbol))" class="RktValLink" pltdoc="x">string->symbol</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/regexp.html#(def._((lib._racket%2Fprivate%2Fbase..rkt)._regexp-split))" class="RktValLink" pltdoc="x">regexp-split</a></span><span class="hspace"> </span><span class="RktVal">#rx"\\."</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/symbols.html#(def._((quote._~23~25kernel)._symbol-~3estring))" class="RktValLink" pltdoc="x">symbol->string</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-~3edatum))" class="RktValLink" pltdoc="x">syntax->datum</a></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">chain</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Check that we have at least hash.key</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/when_unless.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._unless))" class="RktStxLink" pltdoc="x">unless</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._and))" class="RktStxLink" pltdoc="x">and</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._~3e~3d))" class="RktValLink" pltdoc="x">>=</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._length))" class="RktValLink" pltdoc="x">length</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">2</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._not))" class="RktValLink" pltdoc="x">not</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/booleans.html#(def._((quote._~23~25kernel)._eq~3f))" class="RktValLink" pltdoc="x">eq?</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stxops.html#(def._((quote._~23~25kernel)._syntax-e))" class="RktValLink" pltdoc="x">syntax-e</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cadr))" class="RktValLink" pltdoc="x">cadr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">||</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/exns.html#(def._((quote._~23~25kernel)._raise-syntax-error))" class="RktValLink" pltdoc="x">raise-syntax-error</a></span><span class="hspace"> </span><span class="RktVal">#f</span><span class="hspace"> </span><span class="RktVal">"Expected hash.key"</span><span class="hspace"> </span><span class="RktSym">stx</span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktSym">chain</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/stx-patterns.html#(form._((lib._racket%2Fprivate%2Fstxcase-scheme..rkt)._with-syntax))" class="RktStxLink" pltdoc="x">with-syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">h</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._car))" class="RktValLink" pltdoc="x">car</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">ks</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._cdr))" class="RktValLink" pltdoc="x">cdr</a></span><span class="hspace"> </span><span class="RktSym">xs</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPlain"><span class="hspace"> </span></span><span class="hspace"> </span><span class="RktRdr">#'</span><span class="RktPn">(</span><span class="RktSym">hash-refs</span><span class="hspace"> </span><span class="RktSym">h</span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">ks</span><span class="hspace"> </span><span class="RktSym">default</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="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">See if we catch each of the misuses</span></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">eval:96:0: hash.refs: Expected (hash.key0[.key1 ...]</span></p></td></tr><tr><td><p><span class="RktErr">[default])</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">at: chain</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: (hash.refs)</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">eval:98:0: hash.refs: Expected (hash.key0[.key1 ...]</span></p></td></tr><tr><td><p><span class="RktErr">[default])</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">at: 0</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: (hash.refs 0 #f)</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktSym">js</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">eval:99:0: hash.refs: Expected hash.key</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">at: js</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: (hash.refs js #f)</span></p></td></tr><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="hspace"> </span><span class="RktSym">js.</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">eval:100:0: hash.refs: Expected hash.key</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">at: js.</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: (hash.refs js. #f)</span></p></td></tr></table></blockquote><p>Not too bad. Of course, the version with error-checking is quite a bit +longer. Error-checking code generally tends to obscure the logic, and +does here. Fortuantely we’ll soon see how <span class="RktSym"><a href="http://docs.racket-lang.org/syntax/Parsing_Syntax.html#(form._((lib._syntax%2Fparse..rkt)._syntax-parse))" class="RktStxLink" pltdoc="x">syntax-parse</a></span> can +help mitigate that, in much the same way as contracts in normal +Racket or types in Typed Racket.</p><p>Maybe we’re not convinced that writing <span class="RktPn">(</span><span class="RktSym">hash.refs</span><span class="stt"> </span><span class="RktSym">js.a.b.c</span><span class="RktPn">)</span> +is really clearer than <span class="RktPn">(</span><span class="RktSym">hash-refs</span><span class="stt"> </span><span class="RktSym">js</span><span class="stt"> </span><span class="RktVal">'</span><span class="RktVal">(</span><span class="RktVal">a</span><span class="stt"> </span><span class="RktVal">b</span><span class="stt"> </span><span class="RktVal">c</span><span class="RktVal">)</span><span class="RktPn">)</span>. Maybe we +won’t actually use this approach. But the Racket macro system makes it +a possible choice.</p><div class="navsetbottom"><span class="navleft"> </span><span class="navright"><a href="Transform_.html" title="backward to "3 Transform!"" pltdoc="x">← prev</a> <a href="index.html" title="up to "Fear of Macros"" pltdoc="x">up</a> <a href="Syntax_parameters.html" title="forward to "5 Syntax parameters"" pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html> +\ No newline at end of file