[plt-scheme] identifier macros in application position

From: Doug Orleans (dougo at place.org)
Date: Fri Jul 9 00:01:26 EDT 2004

David A. Herman writes:
 > Why doesn't the following work?
 >     ;; add1*: add1 with constant folding
 >     (define-syntax (add1* stx)
 >       (syntax-case stx ()
 >         [(add1* n)
 >          (number? (syntax-object->datum #'n))
 >          (datum->syntax-object stx (add1 (syntax-object->datum #'n)))]
 >         [add1*
 >          (identifier? #'add1*)
 >          #'add1]))
 >     (add1* (+ 2 3))
 > The expression fails to match, which surprised me. Apparently identifier
 > macros only match in operand position. Why is that?

It matches in operator position too, but in that case the value of
`stx' is the entire expression, not just the identifier:

  The transformer for an identifier is applied whenever the identifier
  appears in an expression position -- not just when it appears after
  a parenthesis as `(identifier ...)'. When it does appear as
  `(identifier ...)', the entire `(identifier ...)' expression is
  provided as the argument to the transformer. Otherwise only
  `identifier' is provided to the transformer.

There's no such thing as an "identifier macro"-- all macros are just
identifiers bound to syntax transformers.  Maybe you're being confused
by the difference between `syntax-rules' and `syntax-id-rules'?
(which is irrelevant if you're using `syntax-case')

 > On the one hand, this
 > makes it easy to tell what position the macro is being used in, but on the
 > other hand, if identifier macros matched in any context, you could still
 > distinguish the position by capturing all application contexts in the
 > first patterns followed by the identifier macro, e.g.:
 >     (define-syntax (foo stx)
 >       (syntax-case stx ()
 >         [ ... special cases ... ]
 >         [(foo . anything)
 >          ... default case for application position ... ]
 >         [foo
 >          (identifier? #'foo)
 >          ... operand position case ...]))

This works already:

> (define-syntax (add1* stx)
    (syntax-case stx ()
      [(add1* n)
       (number? (syntax-object->datum #'n))
       (datum->syntax-object stx (add1 (syntax-object->datum #'n)))]
      [(add1* . anything)
        #'(add1 . anything)]  ;; default case for operator position
       (identifier? #'add1*)
> (add1* (+ 2 3))

Or am I misunderstanding your question?

--dougo at place.org

P.S. Since you have an explicit `identifier?' guard, the third case
could appear anywhere-- it doesn't have to be last.  Alternatively,
if it's last, you don't need the `identifier?' guard, except as a
defensive programming tactic.

Posted on the users mailing list.