[racket] ok what's wrong there 'syntax-rule' evaluating its operand (??)

From: Thomas Lynch (thomas.lynch at reasoningtechnology.com)
Date: Thu Jan 15 00:13:47 EST 2015

I reformulated/clarified the question and bumped it over to the developers,
you can find it there.  Thanks for helping with this.

On Thu, Jan 15, 2015 at 12:46 PM, Thomas Lynch <
thomas.lynch at reasoningtechnology.com> wrote:

> Matthias,
>
> I appreciate your patience.  I did see the 'pattern better than direct
> access' and other style discussion on a tutorial on the net, and I do get
> that.  The first macro presented in the original post was to show the
> desired behavior and to show the code runs without errors.  This stands in
> contrast to the define-syntax-rule example, which throws an error - note
> the subject of my post.
>
> You haven't commented on the error or why the syntax rule evaluates the
> operand.  If "macros do not evaluate anything", which was my expectation
> also, and the expansion occurs in hygienically at the scope of the let at
> run time, which was also my expectation,  then where is the 'undefined
> identifier' error coming from?
>
> You can see the error thrown by running the define-syntax-rule example, as
> shown in the original post along with its output.
>
> Thomas
>
>
>
> On Thu, Jan 15, 2015 at 12:07 PM, Matthias Felleisen <matthias at ccs.neu.edu
> > wrote:
>
>>
>> [cc user@ again]
>>
>> There is no bug in syntax-rule/s.
>>
>> Macros do not evaluate anything. They rewrite code. Code refers to
>> identifiers. This relation must remain apparent.
>>
>> That's it. -- Matthias
>>
>>
>>
>>
>>
>>
>> On Jan 14, 2015, at 9:57 PM, Thomas Lynch wrote:
>>
>> As for the demonstrative example at the top of the original post, I now
>> understand you are speaking of clarity and style rather than a functional
>> problem with it. I enjoyed that discussion on clarity, intention, and
>> aesthetics.
>>
>> As for the question of why the 'body' argument is being evaluated as an
>> operand rather as part of the expansion, and thus resulting in an undefined
>> identifier error, am I correct to read your answer above, that this is
>> indeed a bug?  "macro-site variables are bound by macro-contexts" but
>> clearly that is not happening - or the error wouldn't be issued.
>>
>> IMHO the define-syntax-rule would be the clearest implementation for the
>> reader for the reasons you give.  Too bad there is a bug in it.  (The
>> operand should not be evaluated except as part of the macro expansion, as
>> you note.  I am reading you on this correctly?  I have a hard time
>> understanding why an operand to a macro would be evaluated before it is
>> included in the expansion, unless it was a limitation of the interpreter,
>> but if it is a bug, then good as it can be fixed.)
>>
>> On Thu, Jan 15, 2015 at 9:53 AM, Matthias Felleisen <matthias at ccs.neu.edu
>> > wrote:
>>
>>>
>>> On Jan 14, 2015, at 8:14 PM, Thomas Lynch wrote:
>>>
>>> Matthias thank you for fielding my question, though two things are not
>>> clear.  I hope you or someone might clarify.
>>>
>>> Firstly,  is there a reason to prefer the macro you present over the
>>> first one given in the original post.  I believe they both work.  Neither
>>> uses the more elegant syntax-rule.
>>>
>>>
>>>
>>> Code that works is fine. Code that clearly explains its intention is
>>> better. Since syntactic extensions are (basically) extensions to the
>>> grammar, their specification ought to bring across (a) what kind of new
>>> expressions programmers may write down and (b) what these new expressions
>>> mean. I think separating these cleanly is also important.
>>>
>>> With syntax-case, which isn't all that different from syntax-rules, you
>>> get (a) easily:
>>>
>>>   (with-tables stem body ...)
>>>
>>> Compare this to your three or four lines that stx apart. When your
>>> extension is even more complicated, you definitely want this pattern
>>> matching notation because it is close to the way people write grammars and
>>> because you can automatically check certain properties (see syntax-parse).
>>>
>>> For (b), constructing a piece of syntax manually with backquote, comma,
>>> splice is again much more complicated than writing down a rewrite rule. In
>>> particular, you get a really good handle at the manipulation of scope,
>>> which is one of the primary functions of syntactic extensions.
>>>
>>> Racket like Scheme like Lisp is about being able abstract boiler plate.
>>> Syntax-case abstracts your boiler plate for (a) and (b).
>>>
>>> Ideally, I would like to separate (a) from (b) so that programmers can
>>> specify (a) at the module boundary, just like contracts for functions.
>>> That's what I started Ryan on and we ended up syntax-parse. It' s a
>>> fantastic first step but there is work left to do. Probably another
>>> dissertation.
>>>
>>>
>>> Secondly, and this is the question I'm really getting at,  is there a
>>> reason that the operands given to syntax-rules must have identifiers within
>>> lexical scope at the point of the macro call, rather than lexical scope at
>>> the point of their use within the macro?
>>>
>>>
>>> Lexical scope is critical for program comprehension. Programmers read
>>> programs a lot more often than they write them. Lexical scope guarantees
>>> that when they read programs all identifiers are resolved (bound) to a
>>> declaration (binding position) that can be found by reading the text -- not
>>> running the program. By finding it in the text w/o running it, you have a
>>> better chance of predicting what the program does when you run it.
>>>
>>> Macros rewrite program text. In the process, they substitute use-site
>>> code into macro-definition code and macro-definition code is substituted
>>> into use-site code. Each substitution may affect lexical scope when
>>> performed without respect to lexical scope. Each substitution may thus bind
>>> variables to binding occurrences that you can only figure out by running
>>> code. Enforcing that
>>>
>>>   use-site variables are bound by use-context
>>> macro-site variables are bound by macro-contexts
>>>
>>> ___by default___ is called hygienic expansion and almost always gives
>>> you what you want.
>>>
>>> On rare occasion, an extension of Racket's grammar also needs to break
>>> these default rules. syntax-case/parse allow programmers to break those
>>> rules in a way that is still easy to read off from the code.
>>>
>>> That's why it's the right way to go about syntax extensions. -- Matthias
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> Off hand the latter seems to be the proper behavior for a macro,  i.e.
>>> perhaps this is a bug?  Can anyone here tell me why it behaves like this?
>>>
>>>
>>> On Thu, Jan 15, 2015 at 4:12 AM, Matthias Felleisen <
>>> matthias at ccs.neu.edu> wrote:
>>>
>>>>
>>>> You want something like this:
>>>>
>>>> (define-syntax (with-tables stx)
>>>>   (syntax-case stx ()
>>>>     [(with-tables stem body ...)
>>>>      (let ([table-author (datum->syntax stx 'table-author)]
>>>>            ;; ... ditto for other identifiers for which you wish to
>>>> break lexical scope
>>>>            )
>>>>        #`(let ([table-publication (string-append stem "_publication")]
>>>>                [#,table-author (string-append stem "_author")]
>>>>                [table-bridge-publication-author (string-append stem
>>>> "_bridge_publication_author")]
>>>>                [table-unique-counters (string-append stem
>>>> "_unique_counters")])
>>>>            body ...))]))
>>>>
>>>> (with-tables "x" table-author)
>>>>
>>>> ;; ---
>>>>
>>>> To achieve this with syntax-rules would be, well, hard.
>>>>
>>>> ;; ---
>>>>
>>>> The accepted way of writing this macro is:
>>>>
>>>> (define-syntax (with-tables stx)
>>>>   (syntax-case stx ()
>>>>     [(with-tables stem (table-author
>>>>                         ;; ... add other names you wish to bind in body
>>>>                         )
>>>>                   body ...)
>>>>      #`(let ([table-publication (string-append stem "_publication")]
>>>>              [table-author (string-append stem "_author")]
>>>>              [table-bridge-publication-author (string-append stem
>>>> "_bridge_publication_author")]
>>>>              [table-unique-counters (string-append stem
>>>> "_unique_counters")])
>>>>            body ...)]))
>>>>
>>>> (with-tables "x" (table-author) table-author)
>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20150115/c2b79fa8/attachment-0001.html>

Posted on the users mailing list.