[racket] Strange macro behavior with set! and syntax-local-introduce

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Fri May 16 09:59:12 EDT 2014

I think I'm still missing a step here because changing the set! in
funny-set! to a reference makes the "is it an expression" sensitivity
go away (the reference works in both cases), but the explanation would
seem to still apply. Is there something special about set!s that is
contributing here?

Robby


On Fri, May 16, 2014 at 1:47 AM, Matthew Flatt <mflatt at cs.utah.edu> wrote:
> You're running into an awkward corner of the macro system. The corner
> has to do identifiers that are produced by `generate-temporary` and
> then defined within a module.
>
> An identifier produced by `generate-temporary` doesn't claim to be from
> any particular context. If such identifier is defined within a module
> M, how do other uses of the identifier know to refer to the definition
> of M (since the identifier by itself doesn't claim to be from M)?
>
> The answer is that the definition marks the identifier as "introduced
> by a macro into M". It also marks each top-level form in a module with
> the "introduced to module M" context after expansion. The "top-level"
> modifier on "form" is crucial here.
>
> When you wrap `(funny-set! 3)` with `(void ...)`, then you delay its
> expansion until after all top-level forms are expanded. That is,
> `funny-set!` is not long a top-level form within the module.
>
>  * If there's no `void`, then the `funny-set!` form is expanded, and
>    the introduced variable is marked with the "introduced to M"
>    context, and that matches up with the definition.
>
>  * If there's a `void`, then the `(void (funny-set! 3))` form as a
>    whole is marked with "introduced into M", but the `funny-set!` macro
>    is not expanded, yet. Later, when `funny-set!` is expanded as a
>    nested expression, then the introduced identifier is *not* marked
>    with "introduced to M", and so it doesn't match up with the
>    definition.
>
> I'm itching to try a new macro expander that I think would solve this
> problem, and maybe that will happen sometime this year.
>
> Meanwhile, I would write `make-funny-set` as
>
>  (define-syntax (make-funny-set! stx)
>    (syntax-parse stx
>      [(_ v)
>       (define unmarked (generate-temporary))
>       #`(begin
>           (begin-for-syntax (set! funny (quote-syntax #,unmarked)))
>           (define #,unmarked v))]))
>
> and also
>
>  (define-syntax (funny-set! stx)
>    (syntax-parse stx
>      [(_ v)
>       #`(set! #,funny v)]))
>
> By expanding into `begin-for-syntax`, you get the macro expander to
> help you a little more: you don't have to use `syntax-local-introduce`.
> Also, you also avoid the awkward corner, because the still-quoted
> identifier is visible to the macro expander (and therefore available
> for the "introduced to M" mark) instead of sitting in a side channel.
>
> At Thu, 15 May 2014 16:25:47 -0500, Spencer Florence wrote:
>> I'm attempting to write a macro which introduces a new id, then another
>> macro that set!s that id.
>> Example:
>>
>> #lang racket
>> (require (for-syntax syntax/parse racket/syntax))
>> (define-for-syntax funny #f)
>> (define-syntax (make-funny-set! stx)
>>   (syntax-parse stx
>>     [(_ v)
>>      (define unmarked (generate-temporary))
>>      (set! funny (syntax-local-introduce unmarked))
>>      #`(define #,unmarked v)]))
>> (define-syntax (funny-ref stx)
>>   (syntax-parse stx
>>     [(_)
>>      funny]))
>> (define-syntax (funny-set! stx)
>>   (syntax-parse stx
>>     [(_ v)
>>      #`(set! #,(syntax-local-introduce funny) v)]))
>>
>> (make-funny-set! 2)
>> (funny-set! 3)
>> (funny-ref)
>>
>> This program works as I expect, evaluating to 3. However if I change
>> (funny-set! 3) to (void (funny-set! 3)) I get the error: "set!: unbound
>> identifier in module in: g1"
>>
>> I do not get this error if I change (funny-ref) to (void (funny-ref)).
>>
>> If I look at the expansion of the (void (funny-set! 3)) program in
>> drracket's macro stepper the the g1 in (define g1 2) and the g1 in (void
>> (set! g1 3)) have the same color.
>>
>> To keep on with the strange, if I change the #,(syntax-local-introduce
>> funny) inside of funny-set! to #,funny inside the behavior of all programs
>> remains the same.
>>
>> Could someone explain whats going on?
>>
>> --Spencer
>> ____________________
>>   Racket Users list:
>>   http://lists.racket-lang.org/users
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users

Posted on the users mailing list.