127 lines
137 KiB
HTML
127 lines
137 KiB
HTML
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
|
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><meta name="viewport" content="width=device-width, initial-scale=0.8"/><title>16.1 Pattern-Based 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="../manual-style.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../doc-site.css" title="default"/><script type="text/javascript" src="../scribble-common.js"></script><script type="text/javascript" src="../manual-racket.js"></script><script type="text/javascript" src="../manual-racket.js"></script><script type="text/javascript" src="../doc-site.js"></script><script type="text/javascript" src="../local-redirect/local-redirect.js"></script><script type="text/javascript" src="../local-redirect/local-user-redirect.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="doc-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist tocviewlisttopspace"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">►</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">The Racket Guide</a></td></tr></table></div><div class="tocviewsublisttop" style="display: none;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="intro.html" class="tocviewlink" data-pltdoc="x">Welcome to Racket</a></td></tr><tr><td align="right">2 </td><td><a href="to-scheme.html" class="tocviewlink" data-pltdoc="x">Racket Essentials</a></td></tr><tr><td align="right">3 </td><td><a href="datatypes.html" class="tocviewlink" data-pltdoc="x">Built-<wbr></wbr>In Datatypes</a></td></tr><tr><td align="right">4 </td><td><a href="scheme-forms.html" class="tocviewlink" data-pltdoc="x">Expressions and Definitions</a></td></tr><tr><td align="right">5 </td><td><a href="define-struct.html" class="tocviewlink" data-pltdoc="x">Programmer-<wbr></wbr>Defined Datatypes</a></td></tr><tr><td align="right">6 </td><td><a href="modules.html" class="tocviewlink" data-pltdoc="x">Modules</a></td></tr><tr><td align="right">7 </td><td><a href="contracts.html" class="tocviewlink" data-pltdoc="x">Contracts</a></td></tr><tr><td align="right">8 </td><td><a href="i_o.html" class="tocviewlink" data-pltdoc="x">Input and Output</a></td></tr><tr><td align="right">9 </td><td><a href="regexp.html" class="tocviewlink" data-pltdoc="x">Regular Expressions</a></td></tr><tr><td align="right">10 </td><td><a href="control.html" class="tocviewlink" data-pltdoc="x">Exceptions and Control</a></td></tr><tr><td align="right">11 </td><td><a href="for.html" class="tocviewlink" data-pltdoc="x">Iterations and Comprehensions</a></td></tr><tr><td align="right">12 </td><td><a href="match.html" class="tocviewlink" data-pltdoc="x">Pattern Matching</a></td></tr><tr><td align="right">13 </td><td><a href="classes.html" class="tocviewlink" data-pltdoc="x">Classes and Objects</a></td></tr><tr><td align="right">14 </td><td><a href="units.html" class="tocviewlink" data-pltdoc="x">Units</a></td></tr><tr><td align="right">15 </td><td><a href="reflection.html" class="tocviewlink" data-pltdoc="x">Reflection and Dynamic Evaluation</a></td></tr><tr><td align="right">16 </td><td><a href="macros.html" class="tocviewselflink" data-pltdoc="x">Macros</a></td></tr><tr><td align="right">17 </td><td><a href="languages.html" class="tocviewlink" data-pltdoc="x">Creating Languages</a></td></tr><tr><td align="right">18 </td><td><a href="concurrency.html" class="tocv
|
||
|
pattern to an expansion that uses parts of the original syntax that
|
||
|
match parts of the pattern.</p><h5 x-source-module="(lib "scribblings/guide/guide.scrbl")" x-source-pkg="racket-doc" x-part-tag=""define-syntax-rule"">16.1.1<tt> </tt><a name="(part._define-syntax-rule)"></a><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span></h5><p>The simplest way to create a macro is to use
|
||
|
<span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span>:</p><blockquote class="leftindent"><blockquote class="SVInsetFlow"><table cellspacing="0" cellpadding="0" class="boxed RBoxed"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span><span class="hspace"> </span><span class="RktVar">pattern</span><span class="hspace"> </span><span class="RktVar">template</span><span class="RktPn">)</span></td></tr></table></blockquote></blockquote><p>As a running example, consider the <span class="RktSym">swap</span> macro, which swaps
|
||
|
the values stored in two variables. It can be implemented using
|
||
|
<span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span> as follows:</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>The macro is “un-Rackety” in the sense that it
|
||
|
involves side effects on variables—<wbr></wbr>but the point of macros is to let
|
||
|
you add syntactic forms that some other language designer might not
|
||
|
approve.</p></blockquote></blockquote></blockquote><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-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">x</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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>The <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span> form binds a macro that matches a
|
||
|
single pattern. The pattern must always start with an open parenthesis
|
||
|
followed by an identifier, which is <span class="RktSym">swap</span> in this case. After
|
||
|
the initial identifier, other identifiers are <a name="(tech._macro._pattern._variable)"></a><span style="font-style: italic">macro pattern
|
||
|
variables</span> that can match anything in a use of the macro. Thus, this
|
||
|
macro matches the form <span class="RktPn">(</span><span class="RktSym">swap</span><span class="stt"> </span><span class="RktVar">form1</span><span class="stt"> </span><span class="RktVar">form2</span><span class="RktPn">)</span> for any
|
||
|
<span class="RktVar">form1</span> and <span class="RktVar">form2</span>.</p><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>Macro pattern variables are similar to pattern variables for
|
||
|
<span class="RktSym">match</span>. See <a href="match.html" data-pltdoc="x">Pattern Matching</a>.</p></blockquote></blockquote></blockquote><p>After the pattern in <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span> is the
|
||
|
<a name="(tech._template)"></a><span style="font-style: italic">template</span>. The template is used in place of a form that
|
||
|
matches the pattern, except that each instance of a pattern variable
|
||
|
in the template is replaced with the part of the macro use the pattern
|
||
|
variable matched. For example, in</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym">swap</span><span class="hspace"> </span><span class="RktSym">first</span><span class="hspace"> </span><span class="RktSym">last</span><span class="RktPn">)</span></p></blockquote><p>the pattern variable <span class="RktSym">x</span> matches <span class="RktSym">first</span> and <span class="RktSym">y</span>
|
||
|
matches <span class="RktSym">last</span>, so that the expansion is</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-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">first</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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">first</span><span class="hspace"> </span><span class="RktSym">last</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">last</span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><h5 x-source-module="(lib "scribblings/guide/guide.scrbl")" x-source-pkg="racket-doc" x-part-tag=""Lexical_Scope"">16.1.2<tt> </tt><a name="(part._.Lexical_.Scope)"></a>Lexical Scope</h5><p>Suppose that we use the <span class="RktSym">swap</span> macro to swap variables named
|
||
|
<span class="RktSym">tmp</span> and <span class="RktSym">other</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-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="RktVal">5</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">other</span><span class="hspace"> </span><span class="RktVal">6</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="hspace"> </span><span class="RktSym">other</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=pairs.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._list%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="hspace"> </span><span class="RktSym">other</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>The result of the above expression should be <span class="RktRes">(6<span class="stt"> </span>5)</span>. The
|
||
|
naive expansion of this use of <span class="RktSym">swap</span>, however, is</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-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="RktVal">5</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">other</span><span class="hspace"> </span><span class="RktVal">6</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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-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">tmp</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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="hspace"> </span><span class="RktSym">other</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">other</span><span class="hspace"> </span><span class="RktSym">tmp</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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=pairs.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._list%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="hspace"> </span><span class="RktSym">other</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>whose result is <span class="RktRes">(5<span class="stt"> </span>6)</span>. The problem is that the naive
|
||
|
expansion confuses the <span class="RktSym">tmp</span> in the context where <span class="RktSym">swap</span>
|
||
|
is used with the <span class="RktSym">tmp</span> that is in the macro template.</p><p>Racket doesn’t produce the naive expansion for the above use of
|
||
|
<span class="RktSym">swap</span>. Instead, it produces</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-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="RktVal">5</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">other</span><span class="hspace"> </span><span class="RktVal">6</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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">tmp_1</span><span class="hspace"> </span><span class="RktSym">tmp</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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="hspace"> </span><span class="RktSym">other</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">other</span><span class="hspace"> </span><span class="RktSym">tmp_1</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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=pairs.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._list%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="hspace"> </span><span class="RktSym">other</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>with the correct result in <span class="RktRes">(6<span class="stt"> </span>5)</span>. Similarly, in the
|
||
|
example</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktVal">5</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">other</span><span class="hspace"> </span><span class="RktVal">6</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">other</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=pairs.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._list%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">other</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>the expansion is</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">set!_1</span><span class="hspace"> </span><span class="RktVal">5</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">other</span><span class="hspace"> </span><span class="RktVal">6</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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-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">set!_1</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">
|
||
|
assignments introduced by the macro template.</p><p>In other words, Racket’s pattern-based macros automatically maintain
|
||
|
lexical scope, so macro implementors can reason about variable
|
||
|
reference in macros and macro uses in the same way as for functions
|
||
|
and function calls.</p><h5 x-source-module="(lib "scribblings/guide/guide.scrbl")" x-source-pkg="racket-doc" x-part-tag=""define-syntax_and_syntax-rules"">16.1.3<tt> </tt><a name="(part._define-syntax_and_syntax-rules)"></a><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span> and <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</a></span></h5><p>The <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span> form binds a macro that matches a
|
||
|
single pattern, but Racket’s macro system supports transformers that
|
||
|
match multiple patterns starting with the same identifier. To write
|
||
|
such macros, the programmer must use the more general
|
||
|
<span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span> form along with the <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</a></span>
|
||
|
transformer form:</p><blockquote class="leftindent"><blockquote class="SVInsetFlow"><table cellspacing="0" cellpadding="0" class="boxed RBoxed"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktVar">id</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktVar">literal-id</span><span class="hspace"> </span><span class="RktMeta">...</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktVar">pattern</span><span class="hspace"> </span><span class="RktVar">template</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace"> </span><span class="RktMeta">...</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></td></tr></table></blockquote></blockquote><blockquote class="refpara"><blockquote class="refcolumn"><blockquote class="refcontent"><p>The <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span> form is itself a macro
|
||
|
that expands into <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span> with a <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</a></span>
|
||
|
form that contains only one pattern and template.</p></blockquote></blockquote></blockquote><p>For example, suppose we would like a <span class="RktSym">rotate</span> macro that
|
||
|
generalizes <span class="RktSym">swap</span> to work on either two or three identifiers,
|
||
|
so that</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">let</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">red</span><span class="hspace"> </span><span class="RktVal">1</span><span class="RktPn">]</span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">green</span><span class="hspace"> </span><span class="RktVal">2</span><span class="RktPn">]</span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">blue</span><span class="hspace"> </span><span class="RktVal">3</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">rotate</span><span class="hspace"> </span><span class="RktSym">red</span><span class="hspace"> </span><span class="RktSym">green</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">swaps</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">rotate</span><span class="hspace"> </span><span class="RktSym">red</span><span class="hspace"> </span><span class="RktSym">green</span><span class="hspace"> </span><span class="RktSym">blue</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">rotates left</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=pairs.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._list%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym">red</span><span class="hspace"> </span><span class="RktSym">green</span><span class="hspace"> </span><span class="RktSym">blue</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>produces <span class="RktRes">(1<span class="stt"> </span>3<span class="stt"> </span>2)</span>. We can implement <span class="RktSym">rotate</span>
|
||
|
using <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</a></span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">rotate</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</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="RktPn">(</span><span class="RktSym">rotate</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="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</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></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">rotate</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="RktSym">c</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=begin.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._begin%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">begin</a></span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktSym">c</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>The expression <span class="RktPn">(</span><span class="RktSym">rotate</span><span class="stt"> </span><span class="RktSym">red</span><span class="stt"> </span><span class="RktSym">green</span><span class="RktPn">)</span> matches the first pattern
|
||
|
in the <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</a></span> form, so it expands to <span class="RktPn">(</span><span class="RktSym">swap</span><span class="stt"> </span><span class="RktSym">red</span><span class="stt"> </span><span class="RktSym">green</span><span class="RktPn">)</span>. The expression <span class="RktPn">(</span><span class="RktSym">rotate</span><span class="stt"> </span><span class="RktSym">red</span><span class="stt"> </span><span class="RktSym">green</span><span class="stt"> </span><span class="RktSym">blue</span><span class="RktPn">)</span> matches the second
|
||
|
pattern, so it expands to <span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=begin.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._begin%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">begin</a></span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">swap</span><span class="stt"> </span><span class="RktSym">red</span><span class="stt"> </span><span class="RktSym">green</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">swap</span><span class="stt"> </span><span class="RktSym">green</span><span class="stt"> </span><span class="RktSym">blue</span><span class="RktPn">)</span><span class="RktPn">)</span>.</p><h5 x-source-module="(lib "scribblings/guide/guide.scrbl")" x-source-pkg="racket-doc" x-part-tag=""Matching_Sequences"">16.1.4<tt> </tt><a name="(part._.Matching_.Sequences)"></a>Matching Sequences</h5><p>A better <span class="RktSym">rotate</span> macro would allow any number of identifiers,
|
||
|
instead of just two or three. To match a use of <span class="RktSym">rotate</span> with
|
||
|
any number of identifiers, we need a pattern form that has something
|
||
|
like a Kleene star. In a Racket macro pattern, a star is written as
|
||
|
<span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span>.</p><p>To implement <span class="RktSym">rotate</span> with <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span>, we need a base case to
|
||
|
handle a single identifier, and an inductive case to handle more than
|
||
|
one identifier:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">rotate</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</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="RktPn">(</span><span class="RktSym">rotate</span><span class="hspace"> </span><span class="RktSym">a</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=void.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._void%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">void</a></span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym">rotate</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="RktSym">c</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=begin.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._begin%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">begin</a></span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">rotate</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktSym">c</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-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></blockquote><p>When a pattern variable like <span class="RktSym">
|
||
|
a pattern, then it must be followed by <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span> in a template,
|
||
|
too. The pattern variable effectively matches a sequence of zero or
|
||
|
more forms, and it is replaced in the template by the same sequence.</p><p>Both versions of <span class="RktSym">rotate</span> so far are a bit inefficient, since
|
||
|
pairwise swapping keeps moving the value from the first variable into
|
||
|
every variable in the sequence until it arrives at the last one. A
|
||
|
more efficient <span class="RktSym">rotate</span> would move the first value directly to
|
||
|
the last variable. We can use <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span> patterns to implement the
|
||
|
more efficient variant using a helper macro:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">rotate</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</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="RktPn">(</span><span class="RktSym">rotate</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">c</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">shift-to</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">c</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="hspace"> </span><span class="RktSym">a</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">c</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-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><tr><td><span class="hspace"> </span></td></tr><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">shift-to</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</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="R
|
||
|
<span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="stt"> </span><span class="RktSym">to</span><span class="stt"> </span><span class="RktSym">from</span><span class="RktPn">)</span>, which causes the <span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="stt"> </span><span class="RktSym">to</span><span class="stt"> </span><span class="RktSym">from</span><span class="RktPn">)</span>
|
||
|
expression to be duplicated as many times as necessary to use each
|
||
|
identifier matched in the <span class="RktSym">to</span> and <span class="RktSym">from</span>
|
||
|
sequences. (The number of <span class="RktSym">to</span> and <span class="RktSym">from</span> matches must
|
||
|
be the same, otherwise the macro expansion fails with an error.)</p><h5 x-source-module="(lib "scribblings/guide/guide.scrbl")" x-source-pkg="racket-doc" x-part-tag=""Identifier_Macros"">16.1.5<tt> </tt><a name="(part._.Identifier_.Macros)"></a>Identifier Macros</h5><p>Given our macro definitions, the <span class="RktSym">swap</span> or <span class="RktSym">rotate</span>
|
||
|
identifiers must be used after an open parenthesis, otherwise a syntax
|
||
|
error is reported:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=generic-numbers.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._%252B%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">+</a></span><span class="hspace"> </span><span class="RktSym">swap</span><span class="hspace"> </span><span class="RktVal">3</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">eval:2:0: swap: bad syntax</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: swap</span></p></td></tr></table></blockquote><p>An <a name="(tech._identifier._macro)"></a><span style="font-style: italic">identifier macro</span> is a pattern-matching macro that
|
||
|
works when used by itself without parentheses. For example, we
|
||
|
can define <span class="RktSym">val</span> as an identifier macro that expands to
|
||
|
<span class="RktPn">(</span><span class="RktSym">get-val</span><span class="RktPn">)</span>, so <span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=generic-numbers.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._%252B%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">+</a></span><span class="stt"> </span><span class="RktSym">val</span><span class="stt"> </span><span class="RktVal">3</span><span class="RktPn">)</span> would expand to
|
||
|
<span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=generic-numbers.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._%252B%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">+</a></span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">get-val</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktVal">3</span><span class="RktPn">)</span>.</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">val</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-case%2529%2529&version=8.6" class="RktStxLink Sq" data-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="hspace"> </span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">val</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stxops.html%23%2528def._%2528%2528lib._racket%252Fprivate%252Fstx..rkt%2529._identifier%7E3f%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">identifier?</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax</a></span><span class="hspace"> </span><span class="RktSym">val</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">get-val</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><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">
|
||
|
powerful macros and will be explained in the <a href="syntax-case.html" data-pltdoc="x">Mixing Patterns and Expressions: <span class="RktSym"><span class="RktStxLink">syntax-case</span></span></a> section.
|
||
|
For now it is sufficient to know that to define a macro, <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-case%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-case</a></span>
|
||
|
is used in a <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">lambda</a></span>, and its templates must be wrapped with an explicit
|
||
|
<span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax</a></span> constructor. Finally, <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-case%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-case</a></span> clauses
|
||
|
may specify additional guard conditions after the pattern.</p><p>Our <span class="RktSym">val</span> macro uses an <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stxops.html%23%2528def._%2528%2528lib._racket%252Fprivate%252Fstx..rkt%2529._identifier%7E3f%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">identifier?</a></span> condition to ensure that
|
||
|
<span class="RktSym">val</span> <span class="emph">must not</span> be used with parentheses. Instead, the macro raises
|
||
|
a syntax error:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym">val</span><span class="RktPn">)</span></td></tr><tr><td><p><span class="RktErr">eval:8:0: val: bad syntax</span></p></td></tr><tr><td><p><span class="RktErr"></span><span class="hspace"> </span><span class="RktErr">in: (val)</span></p></td></tr></table></blockquote><h5 x-source-module="(lib "scribblings/guide/guide.scrbl")" x-source-pkg="racket-doc" x-part-tag=""set__Transformers"">16.1.6<tt> </tt><a name="(part._set__.Transformers)"></a><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span> Transformers</h5><p>With the above <span class="RktSym">val</span> macro, we still must call <span class="RktSym">put-val!</span> to
|
||
|
change the stored value. It would be more convenient, however, to use
|
||
|
<span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span> directly on <span class="RktSym">val</span>. To invoke the macro when <span class="RktSym">val</span> is
|
||
|
used with <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span>, we create an
|
||
|
<a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=syntax-model.html%23%2528tech._assignment._transformer%2529&version=8.6" class="techoutside Sq" data-pltdoc="x"><span class="techinside">assignment transformer</span></a>
|
||
|
with <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stxtrans.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._make-set%2521-transformer%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">make-set!-transformer</a></span>.
|
||
|
We must also declare <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span> as a literal in the <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-case%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-case</a></span>
|
||
|
literal list.</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">val2</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stxtrans.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._make-set%2521-transformer%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">make-set!-transformer</a></span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-case%2529%2529&version=8.6" class="RktStxLink Sq" data-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="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">val2</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stxops.html%23%2528def._%2528%2528lib._racket%252Fprivate%252Fstx..rkt%2529._identifier%7E3f%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">identifier?</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax</a></span><span class="hspace"> </span><span class="RktSym">val2</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">get-val</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="Rkt
|
||
|
that we’d like to redirect to accessor and mutator functions like
|
||
|
<span class="RktSym">get-val</span> and <span class="RktSym">put-val!</span>. We’d like to be able to
|
||
|
just write:</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym">define-get/put-id</span><span class="hspace"> </span><span class="RktSym">val</span><span class="hspace"> </span><span class="RktSym">get-val</span><span class="hspace"> </span><span class="RktSym">put-val!</span><span class="RktPn">)</span></p></blockquote><p>Naturally, we can implement <span class="RktSym">define-get/put-id</span> as a macro:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">define-get/put-id</span><span class="hspace"> </span><span class="RktSym">id</span><span class="hspace"> </span><span class="RktSym">get</span><span class="hspace"> </span><span class="RktSym">put!</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">id</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stxtrans.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._make-set%2521-transformer%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">make-set!-transformer</a></span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">stx</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-case%2529%2529&version=8.6" class="RktStxLink Sq" data-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="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">id</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/
|
||
|
macro</span>.</p><h5 x-source-module="(lib "scribblings/guide/guide.scrbl")" x-source-pkg="racket-doc" x-part-tag=""pattern-macro-example"">16.1.8<tt> </tt><a name="(part._pattern-macro-example)"></a>Extended Example: Call-by-Reference Functions</h5><p>We can use pattern-matching macros to add a form to Racket
|
||
|
for defining first-order <a name="(tech._call._by._reference)"></a><span style="font-style: italic">call-by-reference</span> functions. When a
|
||
|
call-by-reference function body mutates its formal argument, the
|
||
|
mutation applies to variables that are supplied as actual arguments in
|
||
|
a call to the function.</p><p>For example, if <span class="RktSym">define-cbr</span> is like <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define</a></span> except
|
||
|
that it defines a call-by-reference function, then</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym">define-cbr</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">f</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">b</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</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></td></tr><tr><td><span class="hspace"> </span></td></tr><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-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">1</span><span class="RktPn">]</span><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">y</span><span class="hspace"> </span><span class="RktVal">2</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">f</span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=pairs.html%23%2528def._%2528%2528quote._%7E23%7E25kernel%2529._list%2529%2529&version=8.6" class="RktValLink Sq" data-pltdoc="x">list</a></span><span class="hspace"> </span><span class="RktSym">x</span><span class="hspace"> </span><span class="RktSym">y</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>produces <span class="RktRes">(2<span class="stt"> </span>1)</span>.</p><p>We will implement call-by-reference functions by having function calls
|
||
|
supply accessor and mutators for the arguments, instead of supplying
|
||
|
argument values directly. In particular, for the function <span class="RktSym">f</span>
|
||
|
above, we’ll generate</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">do-f</span><span class="hspace"> </span><span class="RktSym">get-a</span><span class="hspace"> </span><span class="RktSym">get-b</span><span class="hspace"> </span><span class="RktSym">put-a!</span><span class="hspace"> </span><span class="RktSym">put-b!</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">define-get/put-id</span><span class="hspace"> </span><span class="RktSym">a</span><span class="hspace"> </span><span class="RktSym">get-a</span><span class="hspace"> </span><span class="RktSym">put-a!</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">define-get/put-id</span><span class="hspace"> </span><span class="RktSym">b</span><span class="hspace"> </span><span class="RktSym">get-b</span><span class="hspace"> </span><span class="RktSym">put-b!</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</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></td></tr></table></blockquote><p>and redirect a function call <span class="RktPn">(</span><span class="RktSym">f</span><span class="stt"> </span><span class="RktSym">x</span><span class="stt"> </span><span class="RktSym">y</span><span class="RktPn">)</span> to</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym">do-f</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">x</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">y</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">lambda</a></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="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=re
|
||
|
binds <span class="RktSym">f</span> to a macro that expands to a call of <span class="RktSym">do-f</span>.
|
||
|
That is, <span class="RktPn">(</span><span class="RktSym">define-cbr</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">f</span><span class="stt"> </span><span class="RktSym">a</span><span class="stt"> </span><span class="RktSym">b</span><span class="RktPn">)</span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">swap</span><span class="stt"> </span><span class="RktSym">a</span><span class="stt"> </span><span class="RktSym">b</span><span class="RktPn">)</span><span class="RktPn">)</span> needs to generate the
|
||
|
definition</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">f</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</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="RktPn">(</span><span class="RktSym">id</span><span class="hspace"> </span><span class="RktSym">actual</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">do-f</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">actual</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">v</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=set_.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._set%2521%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">set!</a></span><span class="hspace"> </span><span class="RktSym">actual</span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?
|
||
|
using the body of <span class="RktSym">f</span>, this second part is slightly more
|
||
|
complex, so we defer most of it to a <span class="RktSym">define-for-cbr</span> helper
|
||
|
module, which lets us write <span class="RktSym">define-cbr</span> easily enough:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fmisc..rkt%2529._define-syntax-rule%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax-rule</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">define-cbr</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">id</span><span class="hspace"> </span><span class="RktSym">arg</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=begin.html%23%2528form._%2528%2528quote._%7E23%7E25kernel%2529._begin%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">begin</a></span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">id</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</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="RktPn">(</span><span class="RktSym">id</span><span class="hspace"> </span><span class="RktSym">actual</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">do-f</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=lambda.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._lambda%2529%2529&version=8.6"
|
||
|
converts</p><blockquote class="SCodeFlow"><p><span class="RktPn">(</span><span class="RktSym">define-for-cbr</span><span class="hspace"> </span><span class="RktSym">do-f</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="hspace"> </span><span class="RktPn">(</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">swap</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></p></blockquote><p>to the function definition <span class="RktSym">do-f</span> above. Most of the work is
|
||
|
generating a <span class="RktSym">define-get/put-id</span> declaration for each argument,
|
||
|
<span class="RktSym">a</span> and <span class="RktSym">b</span>, and putting them before the body. Normally,
|
||
|
that’s an easy task for <span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span> in a pattern and template, but
|
||
|
this time there’s a catch: we need to generate the names
|
||
|
<span class="RktSym">get-a</span> and <span class="RktSym">put-a!</span> as well as <span class="RktSym">get-b</span> and
|
||
|
<span class="RktSym">put-b!</span>, and the pattern language provides no way to
|
||
|
synthesize identifiers based on existing identifiers.</p><p>As it turns out, lexical scope gives us a way around this problem. The
|
||
|
trick is to iterate expansions of <span class="RktSym">define-for-cbr</span> once for
|
||
|
each argument in the function, and that’s why <span class="RktSym">define-for-cbr</span>
|
||
|
starts with an apparently useless <span class="RktPn">(</span><span class="RktPn">)</span> after the argument
|
||
|
list. We need to keep track of all the arguments seen so far and the
|
||
|
<span class="RktSym">get</span> and <span class="RktSym">put</span> names generated for each, in addition to
|
||
|
the arguments left to process. After we’ve processed all the
|
||
|
identifiers, then we have all the names we need.</p><p>Here is the definition of <span class="RktSym">define-for-cbr</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define-syntax%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define-syntax</a></span><span class="hspace"> </span><span class="RktSym">define-for-cbr</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._syntax-rules%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">syntax-rules</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="RktPn">(</span><span class="RktSym">define-for-cbr</span><span class="hspace"> </span><span class="RktSym">do-f</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">id0</span><span class="hspace"> </span><span class="RktSym">id</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">gens</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">define-for-cbr</span><span class="hspace"> </span><span class="RktSym">do-f</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">id</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">gens</span><span class="hspace"> </span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=stx-patterns.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fstxcase-scheme..rkt%2529._......%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">...</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">id0</span><span class="hspace"> </span><span class="RktSym">get</span><span class="hspace"> </span><span class="RktSym">put</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym">body</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><
|
||
|
<span class="RktSym">put_1</span>, and <span class="RktSym">put_2</span> are inserted by the macro
|
||
|
expander to preserve lexical scope, since the <span class="RktSym">get</span>
|
||
|
generated by each iteration of <span class="RktSym">define-for-cbr</span> should not
|
||
|
bind the <span class="RktSym">get</span> generated by a different iteration. In
|
||
|
other words, we are essentially tricking the macro expander into
|
||
|
generating fresh names for us, but the technique illustrates some
|
||
|
of the surprising power of pattern-based macros with automatic
|
||
|
lexical scope.</p><p>The last expression eventually expands to just</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=define.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fbase..rkt%2529._define%2529%2529&version=8.6" class="RktStxLink Sq" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">do-f</span><span class="hspace"> </span><span class="RktSym">get_1</span><span class="hspace"> </span><span class="RktSym">get_2</span><span class="hspace"> </span><span class="RktSym">put_1</span><span class="hspace"> </span><span class="RktSym">put_2</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="https://download.racket-lang.org/releases/8.6/doc/local-redirect/index.html?doc=reference&rel=let.html%23%2528form._%2528%2528lib._racket%252Fprivate%252Fletstx-scheme..rkt%2529._let%2529%2529&version=8.6" class="RktStxLink Sq" data-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">get_1</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">put_1</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">get_2</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">put_2</span><span class="hspace"> </span><span class="RktSym">tmp</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote><p>which implements the call-by-name function <span class="RktSym">f</span>.</p><p>To summarize, then, we can add call-by-reference functions to
|
||
|
Racket with just three small pattern-based macros:
|
||
|
<span class="RktSym">define-cbr</span>, <span class="RktSym">define-for-cbr</span>, and
|
||
|
<span class="RktSym">define-get/put-id</span>.</p><div class="navsetbottom"><span class="navleft"><form class="searchform"><input class="searchbox" id="searchbox" type="text" tabindex="1" placeholder="...search manuals..." title="Enter a search string to search the manuals" onkeypress="return DoSearchKey(event, this, "8.6", "../");"/></form> <a href="https://docs.racket-lang.org/index.html" title="up to the documentation top" data-pltdoc="x" onclick="return GotoPLTRoot("8.6");">top</a><span class="tocsettoggle"> <a href="javascript:void(0);" title="show/hide table of contents" onclick="TocsetToggle();">contents</a></span></span><span class="navright"> <a href="macros.html" title="backward to "16 Macros"" data-pltdoc="x">← prev</a> <a href="macros.html" title="up to "16 Macros"" data-pltdoc="x">up</a> <a href="proc-macros.html" title="forward to "16.2 General Macro Transformers"" data-pltdoc="x">next →</a></span> </div></div></div><div id="contextindicator"> </div></body></html>
|