16.2.2 Macro Transformer Procedures

Any procedure of one argument can be a macro transformer. As it turns out, the syntax-rules form is a macro that expands to a procedure form. For example, if you evaluate a syntax-rules form directly (instead of placing on the right-hand of a define-syntax form), the result is a procedure:

> (syntax-rules () [(nothing) something])

#<procedure>

Instead of using syntax-rules, you can write your own macro transformer procedure directly using lambda. The argument to the procedure is a syntax object that represents the source form, and the result of the procedure must be a syntax object that represents the replacement form:

> (define-syntax self-as-string
    (lambda (stx)
      (datum->syntax stx
                     (format "~s" (syntax->datum stx)))))
> (self-as-string (+ 1 2))

"(self-as-string (+ 1 2))"

The source form passed to a macro transformer represents an expression in which its identifier is used in an application position (i.e., after a parenthesis that starts an expression), or it represents the identifier by itself if it is used as an expression position and not in an application position.The procedure produced by syntax-rules raises a syntax error if its argument corresponds to a use of the identifier by itself, which is why syntax-rules does not implement an identifier macro.

> (self-as-string (+ 1 2))

"(self-as-string (+ 1 2))"

> self-as-string

"self-as-string"

The define-syntax form supports the same shortcut syntax for functions as define, so that the following self-as-string definition is equivalent to the one that uses lambda explicitly:

> (define-syntax (self-as-string stx)
    (datum->syntax stx
                   (format "~s" (syntax->datum stx))))
> (self-as-string (+ 1 2))

"(self-as-string (+ 1 2))"