[plt-scheme] Non-hygenic Macro Revelation

From: Jay McCarthy (jay.mccarthy at gmail.com)
Date: Thu Mar 25 14:41:58 EDT 2010

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?


[cross-posted on my blog:

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.