diff options
author | Andy Wingo <wingo@pobox.com> | 2011-12-21 20:10:42 -0500 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2011-12-21 20:14:59 -0500 |
commit | dc65d1cf5b59daafdff23d48a48da7f13982efc9 (patch) | |
tree | aa3e25081bc6d7f5492d370210cc5d6845477715 /doc/ref/api-control.texi | |
parent | a2c66014cf4b8799812e45eedbb9b1a2c61236b0 (diff) | |
download | guile-dc65d1cf5b59daafdff23d48a48da7f13982efc9.tar.gz |
document invalidity of (begin) as expression; add back-compat shim
* doc/ref/api-control.texi (begin): Update to distinguish between
splicing begin and sequencing begin.
* module/ice-9/psyntax.scm (expand-expr): Add a back-compatibility shim
for `(begin)'.
* module/ice-9/psyntax-pp.scm: Regenerate.
* test-suite/tests/syntax.test: Update to run illegal (begin) test only
if we are not including deprecated features.
Diffstat (limited to 'doc/ref/api-control.texi')
-rw-r--r-- | doc/ref/api-control.texi | 77 |
1 files changed, 61 insertions, 16 deletions
diff --git a/doc/ref/api-control.texi b/doc/ref/api-control.texi index ad36806f1..957b9a763 100644 --- a/doc/ref/api-control.texi +++ b/doc/ref/api-control.texi @@ -11,7 +11,7 @@ See @ref{Control Flow} for a discussion of how the more general control flow of Scheme affects C code. @menu -* begin:: Evaluating a sequence of expressions. +* begin:: Sequencing and splicing. * if cond case:: Simple conditional evaluation. * and or:: Conditional evaluation of a sequence. * while do:: Iteration mechanisms. @@ -26,38 +26,83 @@ flow of Scheme affects C code. @end menu @node begin -@subsection Evaluating a Sequence of Expressions +@subsection Sequencing and Splicing @cindex begin @cindex sequencing @cindex expression sequencing -The @code{begin} syntax is used for grouping several expressions -together so that they are treated as if they were one expression. -This is particularly important when syntactic expressions are used -which only allow one expression, but the programmer wants to use more -than one expression in that place. As an example, consider the -conditional expression below: +As an expression, the @code{begin} syntax is used to evaluate a sequence +of sub-expressions in order. Consider the conditional expression below: @lisp (if (> x 0) (begin (display "greater") (newline))) @end lisp -If the two calls to @code{display} and @code{newline} were not embedded -in a @code{begin}-statement, the call to @code{newline} would get -misinterpreted as the else-branch of the @code{if}-expression. +If the test is true, we want to display ``greater'' to the current +output port, then display a newline. We use @code{begin} to form a +compound expression out of this sequence of sub-expressions. @deffn syntax begin expr1 expr2 @dots{} -The expression(s) are evaluated in left-to-right order and the value -of the last expression is returned as the value of the +The expression(s) are evaluated in left-to-right order and the value of +the last expression is returned as the value of the @code{begin}-expression. This expression type is used when the expressions before the last one are evaluated for their side effects. - -Guile also allows the expression @code{(begin)}, a @code{begin} with no -sub-expressions. Such an expression returns the `unspecified' value. @end deffn +@cindex splicing +@cindex definition splicing + +The @code{begin} syntax has another role in definition context +(@pxref{Internal Definitions}). A @code{begin} form in a definition +context @dfn{splices} its subforms into its place. For example, +consider the following procedure: + +@lisp +(define (make-seal) + (define-sealant seal open) + (values seal open)) +@end lisp + +Let us assume the existence of a @code{define-sealant} macro that +expands out to some definitions wrapped in a @code{begin}, like so: + +@lisp +(define (make-seal) + (begin + (define seal-tag + (list 'seal)) + (define (seal x) + (cons seal-tag x)) + (define (sealed? x) + (and (pair? x) (eq? (car x) seal-tag))) + (define (open x) + (if (sealed? x) + (cdr x) + (error "Expected a sealed value:" x)))) + (values seal open)) +@end lisp + +Here, because the @code{begin} is in definition context, its subforms +are @dfn{spliced} into the place of the @code{begin}. This allows the +definitions created by the macro to be visible to the following +expression, the @code{values} form. + +It is a fine point, but splicing and sequencing are different. It can +make sense to splice zero forms, because it can make sense to have zero +internal definitions before the expressions in a procedure or lexical +binding form. However it does not make sense to have a sequence of zero +expressions, because in that case it would not be clear what the value +of the sequence would be, because in a sequence of zero expressions, +there can be no last value. Sequencing zero expressions is an error. + +It would be more elegant in some ways to eliminate splicing from the +Scheme language, and without macros (@pxref{Macros}), that would be a +good idea. But it is useful to be able to write macros that expand out +to multiple definitions, as in @code{define-sealant} above, so Scheme +abuses the @code{begin} form for these two tasks. + @node if cond case @subsection Simple Conditional Evaluation |