[plt-scheme] Non-hygenic Macro Revelation

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Thu Mar 25 16:14:01 EDT 2010

Carl Eastlund wrote:
> There are a few ways to do this.  I prefer the option of always having
> an explicit version of the macro, where every name is given in the
> input, and other macros should expand into that.  I find it annoying
> that, for instance, define-struct has no such option.
> 
> Another is to always have an identifier that is explicitly documented
> to provide the context for new definitions, and use that one.

But make sure it's an identifier that isn't used as a reference by the 
macro. For example, don't take the lexical context from the 
'define-pred' identifier, because then you can't give it a lexical 
context where 'define-pred' isn't bound.

Ryan


> Yet another is to specify that the context of the whole term is used,
> and thus any macro expanding into your macro must explicitly use
> datum->syntax to pass along context for the top-level term.
> 
> I consider that list to be in descending order of preference; YMMV.
> 
> Carl Eastlund
> 
> On Thu, Mar 25, 2010 at 2:41 PM, Jay McCarthy <jay.mccarthy at gmail.com> wrote:
>> 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



Posted on the users mailing list.