1.2.6 Contracts on Macro Sub-expressions

Just as procedures often expect certain kinds of values as arguments, macros often have expectations about the expressions they are given. And just as procedures express those expectations via contracts, so can macros, using the expr/c syntax class.

For example, here is a macro myparameterize that behaves like parameterize but enforces the parameter? contract on the parameter expressions.

> (define-syntax (myparameterize stx)
    (syntax-parse stx
      [(_ ((p v:expr) ...) body:expr)
       #:declare p (expr/c #'parameter?
                           #:name "parameter argument")
       #'(parameterize ([p.c v] ...) body)]))
> (myparameterize ([current-input-port
                    (open-input-string "(1 2 3)")])

'(1 2 3)

> (myparameterize (['whoops 'something])

myparameterize: contract violation

  expected: parameter?

  given: 'whoops

  in: parameter?

  contract from: (quote program)

  contract on: parameter argument of myparameterize

  blaming: (quote program)

   (assuming the contract is correct)

  at: eval:3.0

Important: Make sure when using expr/c to use the c attribute. If the macro above had used p in the template, the expansion would have used the raw, unchecked expressions. The expr/c syntax class does not change how pattern variables are bound; it only computes an attribute that represents the checked expression.