Next: Pattern Language, Previous: Macros, Up: Macros
let-syntax
, letrec-syntax
, let*-syntax
and
define-syntax
are analogous to let
, letrec
,
let*
and define
, but they bind syntactic keywords to macro
transformers instead of binding variables to locations that contain
values.
Any argument named transformer-spec must be a macro-transformer expression, which is one of the following:
syntax-rules
.
sc-macro-transformer
,
rsc-macro-transformer
, or er-macro-transformer
.
Bindings should have the form
((keyword transformer-spec) ...)Each keyword is an identifier, each transformer-spec is a a macro-transformer expression, and the body is a sequence of one or more expressions. It is an error for a keyword to appear more than once in the list of keywords being bound.
The expressions are expanded in the syntactic environment obtained by extending the syntactic environment of the
let-syntax
expression with macros whose keywords are the keywords, bound to the specified transformers. Each binding of a keyword has the expressions as its region.(let-syntax ((when (syntax-rules () ((when test stmt1 stmt2 ...) (if test (begin stmt1 stmt2 ...)))))) (let ((if #t)) (when if (set! if 'now)) if)) => now (let ((x 'outer)) (let-syntax ((m (syntax-rules () ((m) x)))) (let ((x 'inner)) (m)))) => outer
The syntax of
letrec-syntax
is the same as forlet-syntax
.The expressions are expanded in the syntactic environment obtained by extending the syntactic environment of the
letrec-syntax
expression with macros whose keywords are the keywords, bound to the specified transformers. Each binding of a keyword has the bindings as well as the expressions within its region, so the transformers can transcribe expressions into uses of the macros introduced by theletrec-syntax
expression.(letrec-syntax ((my-or (syntax-rules () ((my-or) #f) ((my-or e) e) ((my-or e1 e2 ...) (let ((temp e1)) (if temp temp (my-or e2 ...))))))) (let ((x #f) (y 7) (temp 8) (let odd?) (if even?)) (my-or x (let temp) (if y) y))) => 7
The syntax of
let*-syntax
is the same as forlet-syntax
.The expressions are expanded in the syntactic environment obtained by extending the syntactic environment of the
letrec-syntax
expression with macros whose keywords are the keywords, bound to the specified transformers. Each binding of a keyword has the subsequent bindings as well as the expressions within its region. Thus(let*-syntax ((a (syntax-rules ...)) (b (syntax-rules ...))) ...)is equivalent to
(let-syntax ((a (syntax-rules ...))) (let-syntax ((b (syntax-rules ...))) ...))
Keyword is an identifier, and transformer-spec is a macro transformer expression. The syntactic environment is extended by binding the keyword to the specified transformer.
The region of the binding introduced by
define-syntax
is the entire block in which it appears. However, the keyword may only be used after it has been defined.MIT/GNU Scheme permits
define-syntax
to appear both at top level and withinlambda
bodies. The Revised^4 Report permits only top-level uses ofdefine-syntax
.When compiling a program, a top-level instance of
define-syntax
both defines the syntactic keyword and generates code that will redefine the keyword when the program is loaded. This means that the same syntax can be used for defining macros that will be used during compilation and for defining macros to be used at run time.Although macros may expand into definitions and syntax definitions in any context that permits them, it is an error for a definition or syntax definition to shadow a syntactic keyword whose meaning is needed to determine whether some form in the group of forms that contains the shadowing definition is in fact a definition, or, for internal definitions, is needed to determine the boundary between the group and the expressions that follow the group. For example, the following are errors:
(define define 3) (begin (define begin list)) (let-syntax ((foo (syntax-rules () ((foo (proc args ...) body ...) (define proc (lambda (args ...) body ...)))))) (let ((x 3)) (foo (plus x y) (+ x y)) (define foo x) (plus foo x)))