Skip to content

Instantly share code, notes, and snippets.

@ijp
Created January 4, 2012 02:42
Show Gist options
  • Save ijp/1558188 to your computer and use it in GitHub Desktop.
Save ijp/1558188 to your computer and use it in GitHub Desktop.
@node Syntax Parameters
@subsection Syntax Parameters
Syntax parameters@footnote{Described in the paper @cite{Keeping it Clean with
Syntax Parameters} by Barzilay, Culpepper and Flatt.} are a mechanism for rebinding a macro
definition within the dynamic extent of a macro expansion. It provides
a convenient solution to one of the most common types of unhygienic
macro: those that introduce a unhygienic binding each time the macro
is used. Examples include a 'lambda' form with a 'return' keyword , or
class macros that introduce a special 'self' binding.
With syntax parameters, instead of introducing the binding
unhygienically each time, we instead create one binding for the
keyword, which we can then adjust later when we want the keyword to
have a different meaning. As no new bindings are introduced, hygiene is
preserved. This is similar to the dynamic binding mechanisms we have
at run-time like @ref{SRFI-39 - Parameters, parameters} or @ref{Fluids and Dynamic States, fluids}, except that the
dynamic binding only occurs during macro expansion. The code after
macro expansion remains lexically scoped.
@deffn {Syntax} define-syntax-parameter keyword transformer
Binds @var{keyword} to the value obtained by evaluating @var{transformer}. The
@var{transformer} provides the default expansion for the syntax parameter,
and in the absence of @code{syntax-parameterize}, is functionally equivalent
to @code{define-syntax}. Usually, you will just want to have the @var{transformer}
throw a syntax error indicating that the @var{keyword} is supposed to be
used in conjunction with another macro. (see example)
@deffn {Syntax} syntax-parameterize ((keyword transformer) ...) exp ...
Adjusts @var{keyword...} to use the values obtained by evaluating
their @var{transformer...}, in the expansion of the @var{exp...} forms. Each
@var{keyword} must be bound to a syntax-parameter. @code{syntax-parameterize}
differs from @code{let-syntax}, in that the binding is not shadowed, but
adjusted, and so uses of the keyword in the expansion of exp forms use
the new transformers. This is somewhat similar to how @code{parameterize}
adjusts the values of regular parameters, rather than creating new
bindings.
@subsubsection Example
A short example, showing how you can use syntax parameters to create a
variant of 'lambda' that allows early return from the function via the
'return' keyword.
@example
(define-syntax-parameter return
;; by default we bind 'return' to a macro that merely raises a syntax error
(lambda (stx)
(syntax-violation 'return "return used outside of a lambda^" stx)))
(define-syntax lambda^
(syntax-rules ()
[(lambda^ argument-list body bodies ...)
(lambda argument-list
(call-with-current-continuation
(lambda (escape)
;; in the body we adjust the 'return' keyword so that calls
;; to 'return' are replaced with calls to the escape continuation
(syntax-parameterize ([return (syntax-rules ()
[(return vals (... ...))
(escape vals (... ...))])])
body
bodies ...))))]))
;; now we can write functions that return early. Here, 'product' will
;; return immediately if it sees any 0 element.
(define product
(lambda^ (list)
(fold (lambda (n o)
(if (zero? n)
(return 0)
(* n o)))
1
list)))
@end example
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment