Next: , Previous: Defmacros, Up: Macros


6.10.6 Identifier Macros

When the syntax expander sees a form in which the first element is a macro, the whole form gets passed to the macro's syntax transformer. One may visualize this as:

     (define-syntax foo foo-transformer)
     (foo arg...)
     ;; expands via
     (foo-transformer #'(foo arg...))

If, on the other hand, a macro is referenced in some other part of a form, the syntax transformer is invoked with only the macro reference, not the whole form.

     (define-syntax foo foo-transformer)
     foo
     ;; expands via
     (foo-transformer #'foo)

This allows bare identifier references to be replaced programmatically via a macro. syntax-rules provides some syntax to effect this transformation more easily.

— Syntax: identifier-syntax exp

Returns a macro transformer that will replace occurrences of the macro with exp.

For example, if you are importing external code written in terms of fx+, the fixnum addition operator, but Guile doesn't have fx+, you may use the following to replace fx+ with +:

     (define-syntax fx+ (identifier-syntax +))

There is also special support for recognizing identifiers on the left-hand side of a set! expression, as in the following:

     (define-syntax foo foo-transformer)
     (set! foo val)
     ;; expands via
     (foo-transformer #'(set! foo val))
     ;; iff foo-transformer is a "variable transformer"

As the example notes, the transformer procedure must be explicitly marked as being a “variable transformer”, as most macros aren't written to discriminate on the form in the operator position.

— Scheme Procedure: make-variable-transformer transformer

Mark the transformer procedure as being a “variable transformer”. In practice this means that, when bound to a syntactic keyword, it may detect references to that keyword on the left-hand-side of a set!.

          (define bar 10)
          (define-syntax bar-alias
            (make-variable-transformer
             (lambda (x)
               (syntax-case x (set!)
                 ((set! var val) #'(set! bar val))
                 ((var arg ...) #'(bar arg ...))
                 (var (identifier? #'var) #'bar)))))
          
          bar-alias ⇒ 10
          (set! bar-alias 20)
          bar ⇒ 20
          (set! bar 30)
          bar-alias ⇒ 30

There is an extension to identifier-syntax which allows it to handle the set! case as well:

— Syntax: identifier-syntax (var exp1) ((set! var val) exp2)

Create a variable transformer. The first clause is used for references to the variable in operator or operand position, and the second for appearances of the variable on the left-hand-side of an assignment.

For example, the previous bar-alias example could be expressed more succinctly like this:

          (define-syntax bar-alias
            (identifier-syntax
              (var bar)
              ((set! var val) (set! bar val))))

As before, the templates in identifier-syntax forms do not need wrapping in #' syntax forms.