Prev Up Next

Users can create their own special forms by defining macros. A macro is a symbol that has a transformer procedure associated with it. When Scheme encounters a macro-expression -- ie, a form whose head is a macro -- , it applies the macro's transformer to the subforms in the macro-expression, and evaluates the result of the transformation.

Ideally, a macro specifies a purely textual transformation from code text to other code text. This kind of transformation is useful for abbreviating an involved and perhaps frequently occurring textual pattern.

A macro is defined using the special form define-macro (but see sec R.4). For example, if your Scheme lacks the conditional special form when, you could define when as the following macro:

(define-macro when
  (lambda (test . branch)
    (list 'if test
      (cons 'begin branch))))

This defines a when-transformer that would convert a when-expression into the equivalent if-expression. With this macro definition in place, the when-expression

(when (< (pressure tube) 60)
   (open-valve tube)
   (attach floor-pump tube)
   (depress floor-pump 5)
   (detach floor-pump tube)
   (close-valve tube))

will be converted to another expression, the result of applying the when-transformer to the when-expression's subforms:

(apply
  (lambda (test . branch)
    (list 'if test
      (cons 'begin branch)))
  '((< (pressure tube) 60)
      (open-valve tube)
      (attach floor-pump tube)
      (depress floor-pump 5)
      (detach floor-pump tube)
      (close-valve tube)))

The transformation yields the list

(if (< (pressure tube) 60)
    (begin
      (open-valve tube)
      (attach floor-pump tube)
      (depress floor-pump 5)
      (detach floor-pump tube)
      (close-valve tube)))

Scheme will then evaluate this expression, as it would any other.

As an additional example, here is the macro-definition for when's counterpart unless:

(define-macro unless
  (lambda (test . branch)
    (list 'if
          (list 'not test)
          (cons 'begin branch))))

Alternatively, we could invoke when inside unless's definition:

(define-macro unless
  (lambda (test . branch)
    (cons 'when
          (cons (list 'not test) branch))))

Macro expansions can refer to other macros.

Prev Up Next