Syntax parameters allows to rebind syntactic binding dynamically
during macro expandsion. The form resembles parameterize
(see Parameters), but works purely at macro expansion time.
It allows to define a macro that affects other macros hygienically.
It is defined by SRFI-139.
Suppose you want to have a macro (block <body> ...)
that
evaluates expression <body>
sequentially. Inside it,
we want to have another macro (return <expr>)
, which
evaluates <expr>
and then exits (block ...)
,
making the value of <expr>
as the value of (block ...)
,
In other words, the macro block
need to change the behavior of
return
. It can be written, for example, as follows:
(define-syntax block
(er-macro-transformer
(^[f r c]
(quasirename r
`(let/cc ,'return ,@(cdr f)))))
(block (print 1) (print 2) (return 'oops) (print 4))
⇒ print 1, 2, and then returns oops
But note that this needs to insert return
unhyginenically.
It may break, for example, when combined with another library that
uses return
for other purposes.
With syntax parameters, you can write it hygienically:
(define-syntax-parameter return (syntax-rules () ((_ . _) (syntax-error "return outside block")))) (define-syntax block (syntax-rules () ((_ body ...) (let/cc %return (syntax-parameterize ((return (syntax-rules () ((_ expr) (%return expr))))) body ...)))))
The return
has desired effect with block
only if it
refers to the same bindings of define-syntax-parameter
.
Suppose you make the above code into
a library, and the user imports the library with prefix. Then,
the user can refer to the non-local-exit return with the prefix,
and that can coexist of whatever return
defined in the
user’s module.
(use block :prefix b:) (define return ...) (b:block ... (return ...) ; This refers to the 'return' in the current module ... (b:return 'oops) ; This invokes 'return' to exit from the block ... )
[SRFI-139]
Like define-syntax
, binds name with
a macro created by transformer-spec, but the binding
is marked as a syntax parameter, and can be altered with
syntax-parameterize
.
The given transformer-spec works as a default macro, invoked
when no syntax-parameterize
on name is in effect.
The forms allowed in transformer-spec is the same
as define-syntax
.
[SRFI-139] The keys must be identifiers bound to syntax parameters. This form alters the macro transformers of keys with the ones specified by the given transformer-specs, then proceed to compile body …. The altered bindings are effective during the dynamic scope of macro-expansion phase. (Be aware that it has nothing to do with the dynamic scope at runtime.)