31 lines
23 KiB
HTML
31 lines
23 KiB
HTML
<!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> |