1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

document syntax-case

* doc/ref/api-macros.texi: Document syntax-case, and tweak defmacro
  docs.

* doc/ref/api-debug.texi: Move cons-source here.
This commit is contained in:
Andy Wingo 2010-03-19 12:30:31 +01:00
parent a6e60a9571
commit 1fc8dcc7ac
2 changed files with 355 additions and 36 deletions

View file

@ -256,6 +256,17 @@ If the @code{positions} reader option is enabled, each parenthesized
expression will have values set for the @code{filename}, @code{line} and
@code{column} properties.
If you're stuck with defmacros (@pxref{Defmacros}), and want to preserve
source information, the following helper function might be useful to
you:
@deffn {Scheme Procedure} cons-source xorig x y
@deffnx {C Function} scm_cons_source (xorig, x, y)
Create and return a new pair whose car and cdr are @var{x} and @var{y}.
Any source properties associated with @var{xorig} are also associated
with the new pair.
@end deffn
@node Starting a New Stack
@subsubsection Starting a New Stack

View file

@ -128,6 +128,10 @@ same @var{letrec-syntax}.
a beauty worthy of Scheme.
@deffn {Syntax} syntax-rules literals (pattern template)...
Create a syntax transformer that will rewrite an expression using the rules
embodied in the @var{pattern} and @var{template} clauses.
@end deffn
A @code{syntax-rules} macro consists of three parts: the literals (if any), the
patterns, and as many templates as there are patterns.
@ -135,7 +139,6 @@ When the syntax expander sees the invocation of a @code{syntax-rules} macro, it
matches the expression against the patterns, in order, and rewrites the
expression using the template from the first matching pattern. If no pattern
matches, a syntax error is signalled.
@end deffn
@subsubsection Patterns
@ -357,17 +360,322 @@ Primer for the Merely Eccentric}.
@node Syntax Case
@subsection Support for the @code{syntax-case} System
@code{syntax-case} macros are procedural syntax transformers, with a power
worthy of Scheme.
@deffn {Syntax} syntax-case syntax literals (pattern [guard] exp)...
Match the syntax object @var{syntax} against the given patterns, in order. If a
@var{pattern} matches, return the result of evaluating the associated @var{exp}.
@end deffn
Compare the following definitions of @code{when}:
@example
(define-syntax when
(syntax-rules ()
((_ test e e* ...)
(if test (begin e e* ...)))))
(define-syntax when
(lambda (x)
(syntax-case x ()
((_ test e e* ...)
#'(if test (begin e e* ...))))))
@end example
Clearly, the @code{syntax-case} definition is similar to its @code{syntax-rules}
counterpart, and equally clearly there are some differences. The
@code{syntax-case} definition is wrapped in a @code{lambda}, a function of one
argument; that argument is passed to the @code{syntax-case} invocation; and the
``return value'' of the macro has a @code{#'} prefix.
All of these differences stem from the fact that @code{syntax-case} does not
define a syntax transformer itself -- instead, @code{syntax-case} expressions
provide a way to destructure a @dfn{syntax object}, and to rebuild syntax
objects as output.
So the @code{lambda} wrapper is simply a leaky implementation detail, that
syntax transformers are just functions that transform syntax to syntax. This
should not be surprising, given that we have already described macros as
``programs that write programs''. @code{syntax-case} is simply a way to take
apart and put together program text, and to be a valid syntax transformer it
needs to be wrapped in a procedure.
Unlike traditional Lisp macros (@pxref{Defmacros}), @code{syntax-case} macros
transform syntax objects, not raw Scheme forms. Recall the naive expansion of
@code{my-or} given in the previous section:
@example
(let ((t #t))
(my-or #f t))
;; naive expansion:
(let ((t #t))
(let ((t #f))
(if t t t)))
@end example
Raw Scheme forms simply don't have enough information to distinguish the first
two @code{t} instances in @code{(if t t t)} from the third @code{t}. So instead
of representing identifiers as symbols, the syntax expander represents
identifiers as annotated syntax objects, attaching such information to those
syntax objects as is needed to maintain referential transparency.
@deffn {Syntax} syntax form
Create a syntax object wrapping @var{form} within the current lexical context.
@end deffn
Syntax objects are typically created internally to the process of expansion, but
it is possible to create them outside of syntax expansion:
@example
(syntax (foo bar baz))
@result{} #<some representation of that syntax>
@end example
@noindent
However it is more common, and useful, to create syntax objects when building
output from a @code{syntax-case} expression.
@example
(define-syntax add1
(lambda (x)
(syntax-case x ()
((_ exp)
(syntax (+ exp 1))))))
@end example
It is not strictly necessary for a @code{syntax-case} expression to return a
syntax object, because @code{syntax-case} expressions can be used in helper
functions, or otherwise used outside of syntax expansion itself. However a
syntax transformer procedure must return a syntax object, so most uses of
@code{syntax-case} do end up returning syntax objects.
Here in this case, the form that built the return value was @code{(syntax (+ exp
1))}. The interesting thing about this is that within a @code{syntax}
expression, any appearance of a pattern variable is substitued into the
resulting syntax object, carrying with it all relevant metadata from the source
expression, such as lexical identity and source location.
Indeed, a pattern variable may only be referenced from inside a @code{syntax}
form. The syntax expander would raise an error when defining @code{add1} if it
found @var{exp} referenced outside a @code{syntax} form.
Since @code{syntax} appears frequently in macro-heavy code, it has a special
reader macro: @code{#'}. @code{#'foo} is transformed by the reader into
@code{(syntax foo)}, just as @code{'foo} is tranformed into @code{(quote foo)}.
The pattern language used by @code{syntax-case} is conveniently the same
language used by @code{syntax-rules}. Given this, Guile actually defines
@code{syntax-rules} in terms of @code{syntax-case}:
@example
(define-syntax syntax-rules
(lambda (x)
(syntax-case x ()
((_ (k ...) ((keyword . pattern) template) ...)
#'(lambda (x)
(syntax-case x (k ...)
((dummy . pattern) #'template)
...))))))
@end example
And that's that.
@subsubsection Why @code{syntax-case}?
The examples we have shown thus far could just as well have been expressed with
@code{syntax-rules}, and have just shown that @code{syntax-case} is more
verbose, which is true. But there is a difference: @code{syntax-case} creates
@emph{procedural} macros, giving the full power of Scheme to the macro expander.
This has many practical applications.
A common desire is to be able to match a form only if it is an identifier. This
is impossible with @code{syntax-rules}, given the datum matching forms. But with
@code{syntax-case} it is easy:
@deffn {Scheme Procedure} identifier? syntax-object
Returns @code{#t} iff @var{syntax-object} is an identifier.
@end deffn
@example
(define-syntax add1!
(lambda (x)
(syntax-case x ()
((_ var) (identifier? #'var)
#'(set! var (add1 var))))))
(define foo 0)
(add1! foo)
foo @result{} 1
(add1! "not-an-identifier") @result{} error
@end example
With @code{syntax-rules}, the error for @code{(add1! "not-an-identifier")} would
be something like ``invalid @code{set!}''. With @code{syntax-case}, it will say
something like ``invalid @code{add1!}'', because we attach the @dfn{guard
clause} to the pattern: @code{(identifier? #'var)}. This becomes more important
with more complicated macros. It is necessary to use @code{identifier?}, because
to the expander, an identifier is more than a bare symbol.
Note that even in the guard clause, we reference the @var{var} pattern variable
within a @code{syntax} form, via @code{#'var}.
Another common desire is to introduce bindings into the lexical context of the
output expression. One example would be in the so-called ``anaphoric macros'',
like @code{aif}. Anaphoric macros bind some expression to a well-known
identifier, often @code{it}, within their bodies. For example, in @code{(aif
(foo) (bar it))}, @code{it} would be bound to the result of @code{(foo)}.
To begin with, we should mention a solution that doesn't work:
@example
;; doesn't work
(define-syntax aif
(lambda (x)
(syntax-case x ()
((_ test then else)
#'(let ((it test))
(if it then else))))))
@end example
The reason that this doesn't work is that, by default, the expander will
preserve referential transparency; the @var{then} and @var{else} expressions
won't have access to the binding of @code{it}.
But they can, if we explicitly introduce a binding via @code{datum->syntax}.
@deffn {Scheme Procedure} datum->syntax for-syntax datum
Create a syntax object that wraps @var{datum}, within the lexical context
corresponding to the syntax object @var{for-syntax}.
@end deffn
For completeness, we should mention that it is possible to strip the metadata
from a syntax object, returning a raw Scheme datum:
@deffn {Scheme Procedure} syntax->datum syntax-object
Strip the metadata from @var{syntax-object}, returning its contents as a raw
Scheme datum.
@end deffn
In this case we want to introduce @code{it} in the context of the whole
expression, so we can create a syntax object as @code{(datum->syntax x 'it)},
where @code{x} is the whole expression, as passed to the transformer procedure.
Here's another solution that doesn't work:
@example
;; doesn't work either
(define-syntax aif
(lambda (x)
(syntax-case x ()
((_ test then else)
(let ((it (datum->syntax x 'it)))
#'(let ((it test))
(if it then else)))))))
@end example
The reason that this one doesn't work is that there are really two environments
at work here -- the environment of pattern variables, as bound by
@code{syntax-case}, and the environment of lexical variables, as bound by normal
Scheme. Here we need to introduce a piece of Scheme's environment into that of
the syntax expander, and we can do so using @code{syntax-case} itself:
@example
;; works, but is obtuse
(define-syntax aif
(lambda (x)
(syntax-case x ()
((_ test then else)
;; invoking syntax-case on the generated
;; syntax object to expose it to `syntax'
(syntax-case (datum->syntax x 'it) ()
(it
#'(let ((it test))
(if it then else))))))))
(aif (getuid) (display it) (display "none")) (newline)
@print{} 500
@end example
However there are easier ways to write this. @code{with-syntax} is often
convenient:
@deffn {Syntax} with-syntax ((pat val)...) exp...
Bind patterns @var{pat} from their corresponding values @var{val}, within the
lexical context of @var{exp...}.
@example
;; better
(define-syntax aif
(lambda (x)
(syntax-case x ()
((_ test then else)
(with-syntax ((it (datum->syntax x 'it)))
#'(let ((it test))
(if it then else)))))))
@end example
@end deffn
As you might imagine, @code{with-syntax} is defined in terms of
@code{syntax-case}. But even that might be off-putting to you if you are an old
Lisp macro hacker, used to building macro output with @code{quasiquote}. The
issue is that @code{with-syntax} creates a separation between the point of
definition of a value and its point of substitution.
@pindex quasisyntax
@pindex unsyntax
@pindex unsyntax-splicing
So for cases in which a @code{quasiquote} style makes more sense,
@code{syntax-case} also defines @code{quasisyntax}, and the related
@code{unsyntax} and @code{unsyntax-splicing}, abbreviated by the reader as
@code{#`}, @code{#,}, and @code{#,@@}, respectively.
For example, to define a macro that inserts a compile-time timestamp into a
source file, one may write:
@example
(define-syntax display-compile-timestamp
(lambda (x)
(syntax-case x ()
((_)
#`(begin
(display "The compile timestamp was: ")
(display #,(current-time))
(newline))))))
@end example
Finally, we should mention the following helper procedures defined by the core
of @code{syntax-case}:
@deffn {Scheme Procedure} bound-identifier=? a b
Returns @code{#t} iff the syntax objects @var{a} and @var{b} refer to the same
lexically-bound identifier.
@end deffn
@deffn {Scheme Procedure} free-identifier=? a b
Returns @code{#t} iff the syntax objects @var{a} and @var{b} refer to the same
free identifier.
@end deffn
@deffn {Scheme Procedure} generate-temporaries ls
Return a list of temporary identifiers as long as @var{ls} is long.
@end deffn
Readers interested in further information on @code{syntax-case} macros should
see R. Kent Dybvig's excellent @cite{The Scheme Programming Language}, either
edition 3 or 4, in the chapter on syntax. Dybvig was the primary author of the
@code{syntax-case} system. The book itself is available online at
@uref{http://scheme.com/tspl4/}.
@node Defmacros
@subsection Lisp-style Macro Definitions
In Lisp-like languages, the traditional way to define macros is very
similar to procedure definitions. The key differences are that the
macro definition body should return a list that describes the
transformed expression, and that the definition is marked as a macro
definition (rather than a procedure definition) by the use of a
different definition keyword: in Lisp, @code{defmacro} rather than
@code{defun}, and in Scheme, @code{define-macro} rather than
@code{define}.
The traditional way to define macros in Lisp is very similar to procedure
definitions. The key differences are that the macro definition body should
return a list that describes the transformed expression, and that the definition
is marked as a macro definition (rather than a procedure definition) by the use
of a different definition keyword: in Lisp, @code{defmacro} rather than
@code{defun}, and in Scheme, @code{define-macro} rather than @code{define}.
@fnindex defmacro
@fnindex define-macro
@ -390,37 +698,37 @@ is the same as
The difference is analogous to the corresponding difference between
Lisp's @code{defun} and Scheme's @code{define}.
@code{false-if-exception}, from the @file{boot-9.scm} file in the Guile
distribution, is a good example of macro definition using
@code{defmacro}:
Having read the previous section on @code{syntax-case}, it's probably clear that
Guile actually implements defmacros in terms of @code{syntax-case}, applying the
transformer on the expression between invocations of @code{syntax->datum} and
@code{datum->syntax}. This realization leads us to the problem with defmacros,
that they do not preserve referential transparency. One can be careful to not
introduce bindings into expanded code, via liberal use of @code{gensym}, but
there is no getting around the lack of referential transparency for free
bindings in the macro itself.
@lisp
(defmacro false-if-exception (expr)
`(catch #t
(lambda () ,expr)
(lambda args #f)))
@end lisp
Even a macro as simple as our @code{when} from before is difficult to get right:
@noindent
The effect of this definition is that expressions beginning with the
identifier @code{false-if-exception} are automatically transformed into
a @code{catch} expression following the macro definition specification.
For example:
@example
(define-macro (when cond exp . rest)
`(if ,cond
(begin ,exp . ,rest)))
@lisp
(false-if-exception (open-input-file "may-not-exist"))
@equiv{}
(catch #t
(lambda () (open-input-file "may-not-exist"))
(lambda args #f))
@end lisp
(when #f (display "Launching missiles!\n"))
@result{} #f
@deffn {Scheme Procedure} cons-source xorig x y
@deffnx {C Function} scm_cons_source (xorig, x, y)
Create and return a new pair whose car and cdr are @var{x} and @var{y}.
Any source properties associated with @var{xorig} are also associated
with the new pair.
@end deffn
(let ((if list))
(when #f (display "Launching missiles!\n")))
@print{} Launching missiles!
@result{} (#f #<unspecified>)
@end example
Guile's perspective is that defmacros have had a good run, but that modern
macros should be written with @code{syntax-rules} or @code{syntax-case}. There
are still many uses of defmacros within Guile itself, but we will be phasing
them out over time. Of course we won't take away @code{defmacro} or
@code{define-macro} themselves, as there is lots of code out there that uses
them.
@node Identifier Macros