1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 03:30:27 +02:00

document syntax parameters

* doc/ref/api-macros.texi (Macros): Add subsection for "Syntax Parameters"
This commit is contained in:
Ian Price 2012-01-07 01:59:33 +00:00 committed by Andy Wingo
parent 49d09292ac
commit 729b62bd95

View file

@ -40,6 +40,7 @@ languages}, or EDSLs.}.
* Syntax Case:: Procedural, hygienic macros.
* Defmacros:: Lisp-style macros.
* Identifier Macros:: Identifier macros.
* Syntax Parameters:: Syntax Parameters
* Eval When:: Affecting the expand-time environment.
* Internal Macros:: Macros as first-class values.
@end menu
@ -861,6 +862,81 @@ wrapping in @code{#'} syntax forms.
@end deffn
@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 @code{lambda} form with a @code{return} keyword, or
class macros that introduce a special @code{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} 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, for example:
@example
(define-syntax-parameter return
(lambda (stx)
(syntax-violation 'return "return used outside of a lambda^" stx)))
@end example
@end deffn
@deffn {Syntax} syntax-parameterize ((keyword transformer) @dots{}) exp @dots{}
Adjusts @var{keyword} @dots{} to use the values obtained by evaluating
their @var{transformer} @dots{}, in the expansion of the @var{exp} @dots{}
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 somewhatsimilar to how @code{parameterize}
adjusts the values of regular parameters, rather than creating new
bindings.
@example
(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
@end deffn
@node Eval When
@subsection Eval-when