mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
document syntax parameters
* doc/ref/api-macros.texi (Macros): Add subsection for "Syntax Parameters"
This commit is contained in:
parent
49d09292ac
commit
729b62bd95
1 changed files with 76 additions and 0 deletions
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue