[plt-scheme] Non-hygenic Macro Revelation

From: Jay McCarthy (jay.mccarthy at gmail.com)
Date: Thu Mar 25 15:53:33 EDT 2010

On Thu, Mar 25, 2010 at 1:47 PM, David Herman <dherman at ccs.neu.edu> wrote:
> It's a matter of the documented behavior of the macro. Sometimes you want it to work one way, sometimes another. Here's my standard example. Imagine that you implement `while' to implicitly bind `break'. Let's pretend that `break' is implicitly bound here:
>   (define-syntax-rule (while test e ...)
>     (let/ec break
>       (let loop ()
>         (when test
>           e ...
>           (loop)))))
> Now imagine you want to implement `for' on top of this:
>   (define-syntax-rule (for lo-e hi-e e ...)
>     (let ([i lo-e]
>           [hi hi-e])
>       (while (< i hi)
>         e ...
>         (set! i (add1 i)))))
> In this case, you want part of the public interface of `for' to be that it binds `break'.

Thanks for your explanation. I agree.

The weirdness is that for can't make this decision without knowing
exactly what context while uses. If while uses the context of the
first 'e', then the 'for' body gets 'break' for free. If while uses
stx or test, then for has to play wild games to make it work.

I guess I've come to the realization that I have to go back over years
of macros and document where they bind their names.


> But now imagine you want to use `while' internally as part of an implementation:
>   (define-syntax-rule (do-100x e)
>     (let ([i 0])
>       (while (< i 100)
>         e
>         (set! i (add1 i)))))
> Then you might *not* want the binding of `break' to be exposed. So there's no "right" behavior; it depends on what you want your macro to do. And you definitely have to inform users of the behavior.
> Dave
> ----- Original Message -----
> From: "Jay McCarthy" <jay.mccarthy at gmail.com>
> To: "PLT-Scheme List" <plt-scheme at list.cs.brown.edu>
> Sent: Thursday, March 25, 2010 11:41:58 AM GMT -08:00 US/Canada Pacific
> Subject: [plt-scheme] Non-hygenic Macro Revelation
> I've always used the pattern
> (datum->syntax stx (string->symbol (format "~a?" (syntax->datum #'id))))
> when defining, for example, predicates of inputs to macros. (stx is
> the syntax object given to the transformer.)
> This gives the new identifier the same lexical scope as the call to
> the macro. Yesterday I noticed that this causes a problem with trivial
> macro combinations.
> (define-syntax (define-pred stx)
>  (syntax-case stx ()
>    [(_ id)
>     (with-syntax ([id? (datum->syntax stx (string->symbol (format
> "~a?" (syntax->datum #'id))))])
>       (syntax/loc stx
>         (define (id? x) #t)))]))
> (define-syntax-rule (define-pred-wrap i)
>  (define-pred i))
> (define-pred-wrap x)
> In this example x? is unbound, because it gets the lexical context of
> the define-pred-wrap macro, not the user's program. This can be easily
> fixed by using
> (datum->syntax #'id (string->symbol (format "~a?" (syntax->datum #'id))))
> instead. In this case the predicate gets the same context as the
> identifier used to construct it.
> I'm not sure when it is appropriate to do one versus the other. One
> idea is to use stx when the new identifier is based on multiple
> inputs, but otherwise use the context of the base identifier.
> (However, that rule would have still caused the problem that
> instigated this.) If there was a way to compare contexts, I think I
> would want (if (context=? #'id1 #'id2 ...) #'id1 stx), so I got the
> shared identifier context or the macro invocation context. However, I
> don't think such an operation exists. You could probably make one by
> creating a new identifier per input identifier, then use
> bound-identifier=? to see if they are bound in the same context.
> Is there a convention I don't know about?
> Jay
> [cross-posted on my blog:
> http://jay-mccarthy.blogspot.com/2010/03/non-hygenic-macro-revelation.html]
> --
> Jay McCarthy <jay at cs.byu.edu>
> Assistant Professor / Brigham Young University
> http://teammccarthy.org/jay
> "The glory of God is Intelligence" - D&C 93
> _________________________________________________
>  For list-related administrative tasks:
>  http://list.cs.brown.edu/mailman/listinfo/plt-scheme

Jay McCarthy <jay at cs.byu.edu>
Assistant Professor / Brigham Young University

"The glory of God is Intelligence" - D&C 93

Posted on the users mailing list.