diff options
Diffstat (limited to 'doc/ref/scheme-control.texi')
-rw-r--r-- | doc/ref/scheme-control.texi | 823 |
1 files changed, 823 insertions, 0 deletions
diff --git a/doc/ref/scheme-control.texi b/doc/ref/scheme-control.texi new file mode 100644 index 000000000..dd5f9be53 --- /dev/null +++ b/doc/ref/scheme-control.texi @@ -0,0 +1,823 @@ +@page +@node Control Mechanisms +@chapter Controlling the Flow of Program Execution + +@menu +* begin:: Evaluating a sequence of expressions. +* if cond case:: Simple conditional evaluation. +* and or:: Conditional evaluation of a sequence. +* while do:: Iteration mechanisms. +* Continuations:: Continuations. +* Multiple Values:: Returning and accepting multiple values. +* Exceptions:: Throwing and catching exceptions. +* Error Reporting:: Procedures for signaling errors. +* Dynamic Wind:: Guarding against non-local entrance/exit. +@end menu + + +@node begin +@section Evaluating a Sequence of Expressions + +@c FIXME::martin: Review me! + +@c FIXME::martin: Maybe add examples? + +@cindex begin +@cindex sequencing +@cindex expression sequencing + +@code{begin} is used for grouping several expression together so that +they syntactically 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: + +@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. + +@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 +@code{begin}-expression. This expression type is used when the +expressions before the last one are evaluated for their side effects. +@end deffn + +@node if cond case +@section Simple Conditional Evaluation + +@c FIXME::martin: Review me! + +@c FIXME::martin: Maybe add examples? + +@cindex conditional evaluation +@cindex if +@cindex case +@cindex cond + +Guile provides three syntactic constructs for conditional evaluation. +@code{if} is the normal if-then-else expression (with an optional else +branch), @code{cond} is a conditional expression with multiple branches +and @code{case} branches if an expression has one of a set of constant +values. + +@deffn syntax if test consequent [alternate] +All arguments may be arbitrary expressions. First, @var{test} is +evaluated. If it returns a true value, the expression @var{consequent} +is evaluated and @var{alternate} is ignoret. If @var{test} evaluates to +@code{#f}, @var{alternate} is evaluated instead. The value of the +evaluated branch (@var{consequent} or @var{alternate}) is returned as +the value of the @code{if} expression. + +When @var{alternate} is omitted and the @var{test} evaluates to +@code{#f}, the value of the expression is not specified. +@end deffn + +@deffn syntax cond clause1 clause2 @dots{} +Each @code{cond}-clause must look like this: + +@lisp +(@var{test} @var{expression} @dots{}) +@end lisp + +where @var{test} and @var{expression} are arbitrary expression, or like +this + +@lisp +(@var{test} => @var{expression} +@end lisp + +where @var{expression} must evaluate to a procedure. + +The @var{test}s of the clauses are evaluated in order and as soon as one +of them evaluates to a true values, the corresponding @var{expression}s +are evaluated in order and the last value is returned as the value of +the @code{cond}-expression. For the @code{=>} clause type, +@var{expression} is evaluated and the resulting procedure is applied to +the value of @var{test}. The result of this procedure application is +then the result of the @code{cond}-expression. + +The @var{test} of the last @var{clause} may be the keyword @code{else}. +Then, if none of the preceding @var{test}s is true, the @var{expression}s following the @code{else} are evaluated to produce the result of the @code{cond}-expression. +@end deffn + +@deffn syntax case key clause1 clause2 @dots{} +@var{key} may be any expression, the @var{clause}s must have the form + +@lisp +((@var{datum1} @dots{}) @var{expr1} @var{expr2} @dots{}) +@end lisp + +and the last @var{clause} may have the form + +@lisp +(else @var{expr1} @var{expr2} @dots{}) +@end lisp + +All @var{datum}s must be distinct. First, @var{key} is evaluated. The +the result of this evaluation is compared against all @var{datum}s using +@code{eqv?}. When this comparison succeeds, the epression(s) following +the @var{datum} are evaluated from left to right, returning the value of +the last expression as the result of the @code{case} expression. + +If the @var{key} matches no @var{datum} and there is an +@code{else}-clause, the expressions following the @code{else} are +evaluated. If there is no such clause, the result of the expression is +unspecified. +@end deffn + + +@node and or +@section Conditional Evaluation of a Sequence of Expressions + +@c FIXME::martin: Review me! + +@c FIXME::martin: Maybe add examples? + +@code{and} and @code{or} evaluate all their arguments, similar to +@code{begin}, but evaluation stops as soon as one of the expressions +evaluates to false or true, respectively. + +@deffn syntax and expr @dots{} +Evaluate the @var{expr}s from left to right and stop evaluation as soon +as one expression evaluates to @code{#f}; the remaining expressions are +not evaluated. The value of the last evaluated expression is returned. +If no expression evaluates to @code{#f}, the value of the last +expression is returned. + +If used without expressions, @code{#t} is returned. +@end deffn + +@deffn syntax or expr @dots{} +Evaluate the @var{expr}s from left to right and stop evaluation as soon +as one expression evaluates to a true value (that is, a value different +from @code{#f}); the remaining expressions are not evaluated. The value +of the last evaluated expression is returned. If all expressions +evaluate to @code{#f}, @code{#f} is returned. + +If used without expressions, @code{#f} is returned. +@end deffn + + +@node while do +@section Iteration mechanisms + +@c FIXME::martin: Review me! + +@c FIXME::martin: Maybe add examples? + +@cindex iteration +@cindex looping +@cindex named let + +Scheme has only few iteration mechanisms, mainly because iteration in +Scheme programs is normally expressed using recursion. Nevertheless, +R5RS defines a construct for programming loops, calling @code{do}. In +addition, Guile has an explicit looping syntax called @code{while}. + +@deffn syntax do ((variable1 init1 step1) @dots{}) (test expr @dots{}) command @dots{} +The @var{init} expressions are evaluated and the @var{variables} are +bound to their values. Then looping starts with testing the @var{test} +expression. If @var{test} evaluates to a true value, the @var{expr} +following the @var{test} are evaluated and the value of the last +@var{expr} is returned as the value of the @code{do} expression. If +@var{test} evaluates to false, the @var{command}s are evaluated in +order, the @var{step}s are evaluated and stored into the @var{variables} +and the next iteration starts. + +Any of the @var{step} expressions may be omitted, so that the +corresponding variable is not changed during looping. +@end deffn + +@deffn syntax while cond body @dots{} +Evaluate all expressions in @var{body} in order, as long as @var{cond} +evaluates to a true value. The @var{cond} expression is tested before +every iteration, so that the body is not evaluated at all if @var{cond} +is @code{#f} right from the start. +@end deffn + +@cindex named let +Another very common way of expressing iteration in Scheme programs is +the use of the so-called @dfn{named let}. + +Named let is a variant of @code{let} which creates a procedure and calls +it in one step. Because of the newly created procedure, named let is +more powerful than @code{do}--it can be used for iteration, but also +for arbitrary recursion. + +@deffn syntax let variable bindings body +For the definition of @var{bindings} see the documentation about +@code{let} (@pxref{Local Bindings}). + +Named @code{let} works as follows: + +@itemize @bullet +@item +A new procedure which accepts as many arguments as are in @var{bindings} +is created and bound locally (using @code{let}) to @var{variable}. The +new procedure's formal argument names are the name of the +@var{variables}. + +@item +The @var{body} expressions are inserted into the newly created procedure. + +@item +The procedure is called with the @var{init} expressions as the formal +arguments. +@end itemize + +The next example implements a loop which iterates (by recursion) 1000 +times. + +@lisp +(let lp ((x 1000)) + (if (positive? x) + (lp (- x 1)) + x)) +@result{} +0 +@end lisp +@end deffn + + +@node Continuations +@section Continuations + +@cindex call/cc +@cindex call-with-current-continuation +The ability to explicitly capture continuations using +@code{call-with-current-continuation} (also often called @code{call/cc} +for short), and to invoke such continuations later any number of times, +and from any other point in a program, provides maybe the most powerful +control structure known. All other control structures, such as loops +and coroutines, can be emulated using continuations. + +@c NJFIXME - need a little something here about what continuations are +@c and what they do for you. + +The implementation of continuations in Guile is not as efficient as one +might hope, because it is constrained by the fact that Guile is designed +to cooperate with programs written in other languages, such as C, which +do not know about continuations. So continuations should be used when +there is no other simple way of achieving the desired behaviour, or +where the advantages of the elegant continuation mechanism outweigh the +need for optimum performance. If you find yourself using @code{call/cc} +for escape procedures and your program is running too slow, you might +want to use exceptions (@pxref{Exceptions}) instead. + +@rnindex call-with-current-continuation +@deffn primitive call-with-current-continuation proc +Capture the current continuation and call @var{proc} with the captured +continuation as the single argument. This continuation can then be +called with arbitrarily many arguments. Such a call will work like a +goto to the invocation location of +@code{call-with-current-continuation}, passing the arguments in a way +that they are returned by the call to +@code{call-with-current-continuation}. Since it is legal to store the +captured continuation in a variable or to pass it to other procedures, +it is possible that a procedure returns more than once, even if it is +called only one time. This can be confusing at times. +@end deffn + +@c FIXME::martin: Better example needed. +@lisp +(define kont #f) +(call-with-current-continuation + (lambda (k) + (set! kont k) + 1)) +@result{} +1 + +(kont 2) +@result{} +2 +@end lisp + + +@node Multiple Values +@section Returning and Accepting Multiple Values + +@c FIXME::martin: Review me! +@cindex multiple values +@cindex receive + +Scheme allows a procedure to return more than one value to its caller. +This is quite different to other languages which only allow +single-value returns. Returning multiple values is different from +returning a list (or pair or vector) of values to the caller, because +conceptionally not @emph{one} compound object is returned, but several +distinct values. + +The primitive procedures for handling multiple values are @code{values} +and @code{call-with-values}. @code{values} is used for returning +multiple values from a procedure. This is done by placing a call to +@code{values} with zero or more arguments in tail position in a +procedure body. @code{call-with-values} combines a procedure returning +multiple values with a procedure which accepts these values as +parameters. + +@rnindex values +@deffn primitive values expr @dots{} +Delivers all of its arguments to its continuation. Except for +continuations created by the @code{call-with-values} procedure, +all continuations take exactly one value. The effect of +passing no value or more than one value to continuations that +were not created by @code{call-with-values} is unspecified. +@end deffn + +@rnindex call-with-values +@deffn primitive call-with-values producer consumer +Calls its @var{producer} argument with no values and a +continuation that, when passed some values, calls the +@var{consumer} procedure with those values as arguments. The +continuation for the call to @var{consumer} is the continuation +of the call to @code{call-with-values}. + +@example +(call-with-values (lambda () (values 4 5)) + (lambda (a b) b)) + ==> 5 + +@end example +@example +(call-with-values * -) ==> -1 +@end example +@end deffn + +In addition to the fundamental procedures described above, Guile has a +module which exports a syntax called @code{receive}, which is much more +convenient. If you want to use it in your programs, you have to load +the module @code{(ice-9 receive)} with the statement + +@lisp +(use-modules (ice-9 receive)) +@end lisp + +@deffn {library syntax} receive formals expr body @dots{} +Evaluate the expression @var{expr}, and bind the result values (zero or +more) to the formal arguments in the formal argument list @var{formals}. +@var{formals} must have the same syntax like the formal argument list +used in @code{lambda} (@pxref{Lambda}). After binding the variables, +the expressions in @var{body} @dots{} are evaluated in order. +@end deffn + + +@node Exceptions +@section Exceptions +@cindex error handling +@cindex exception handling + +A common requirement in applications is to want to jump +@dfn{non-locally} from the depths of a computation back to, say, the +application's main processing loop. Usually, the place that is the +target of the jump is somewhere in the calling stack of procedures that +called the procedure that wants to jump back. For example, typical +logic for a key press driven application might look something like this: + +@example +main-loop: + read the next key press and call dispatch-key + +dispatch-key: + lookup the key in a keymap and call an appropriate procedure, + say find-file + +find-file: + interactively read the required file name, then call + find-specified-file + +find-specified-file: + check whether file exists; if not, jump back to main-loop + @dots{} +@end example + +The jump back to @code{main-loop} could be achieved by returning through +the stack one procedure at a time, using the return value of each +procedure to indicate the error condition, but Guile (like most modern +programming languages) provides an additional mechanism called +@dfn{exception handling} that can be used to implement such jumps much +more conveniently. + +@menu +* Exception Terminology:: Different ways to say the same thing. +* Catch:: Setting up to catch exceptions. +* Throw:: Throwing an exception. +* Lazy Catch:: Catch without unwinding the stack. +* Exception Implementation:: How Guile implements exceptions. +@end menu + + +@node Exception Terminology +@subsection Exception Terminology + +There are several variations on the terminology for dealing with +non-local jumps. It is useful to be aware of them, and to realize +that they all refer to the same basic mechanism. + +@itemize @bullet +@item +Actually making a non-local jump may be called @dfn{raising an +exception}, @dfn{raising a signal}, @dfn{throwing an exception} or +@dfn{doing a long jump}. When the jump indicates an error condition, +people may talk about @dfn{signalling}, @dfn{raising} or @dfn{throwing} +@dfn{an error}. + +@item +Handling the jump at its target may be referred to as @dfn{catching} or +@dfn{handling} the @dfn{exception}, @dfn{signal} or, where an error +condition is involved, @dfn{error}. +@end itemize + +Where @dfn{signal} and @dfn{signalling} are used, special care is needed +to avoid the risk of confusion with POSIX signals. (Especially +considering that Guile handles POSIX signals by throwing a corresponding +kind of exception: REFFIXME.) + +This manual prefers to speak of throwing and catching exceptions, since +this terminology matches the corresponding Guile primitives. + + +@node Catch +@subsection Catching Exceptions + +@code{catch} is used to set up a target for a possible non-local jump. +The arguments of a @code{catch} expression are a @dfn{key}, which +restricts the set of exceptions to which this @code{catch} applies, a +thunk that specifies the @dfn{normal case} code --- i.e. what should +happen if no exceptions are thrown --- and a @dfn{handler} procedure +that says what to do if an exception is thrown. Note that if the +@dfn{normal case} thunk executes @dfn{normally}, which means without +throwing any exceptions, the handler procedure is not executed at all. + +When an exception is thrown using the @code{throw} primitive, the first +argument of the @code{throw} is a symbol that indicates the type of the +exception. For example, Guile throws an exception using the symbol +@code{numerical-overflow} to indicate numerical overflow errors such as +division by zero: + +@lisp +(/ 1 0) +@result{} +ABORT: (numerical-overflow) +@end lisp + +The @var{key} argument in a @code{catch} expression corresponds to this +symbol. @var{key} may be a specific symbol, such as +@code{numerical-overflow}, in which case the @code{catch} applies +specifically to exceptions of that type; or it may be @code{#t}, which +means that the @code{catch} applies to all exceptions, irrespective of +their type. + +The second argument of a @code{catch} expression should be a thunk +(i.e. a procedure that accepts no arguments) that specifies the normal +case code. The @code{catch} is active for the execution of this thunk, +including any code called directly or indirectly by the thunk's body. +Evaluation of the @code{catch} expression activates the catch and then +calls this thunk. + +The third argument of a @code{catch} expression is a handler procedure. +If an exception is thrown, this procedure is called with exactly the +arguments specified by the @code{throw}. Therefore, the handler +procedure must be designed to accept a number of arguments that +corresponds to the number of arguments in all @code{throw} expressions +that can be caught by this @code{catch}. + +@deffn primitive catch key thunk handler +Invoke @var{thunk} in the dynamic context of @var{handler} for +exceptions matching @var{key}. If thunk throws to the symbol +@var{key}, then @var{handler} is invoked this way: +@lisp +(handler key args ...) +@end lisp + +@var{key} is a symbol or @code{#t}. + +@var{thunk} takes no arguments. If @var{thunk} returns +normally, that is the return value of @code{catch}. + +Handler is invoked outside the scope of its own @code{catch}. +If @var{handler} again throws to the same key, a new handler +from further up the call chain is invoked. + +If the key is @code{#t}, then a throw to @emph{any} symbol will +match this call to @code{catch}. +@end deffn + +If the handler procedure needs to match a variety of @code{throw} +expressions with varying numbers of arguments, you should write it like +this: + +@lisp +(lambda (key . args) + @dots{}) +@end lisp + +@noindent +The @var{key} argument is guaranteed always to be present, because a +@code{throw} without a @var{key} is not valid. The number and +interpretation of the @var{args} varies from one type of exception to +another, but should be specified by the documentation for each exception +type. + +Note that, once the handler procedure is invoked, the catch that led to +the handler procedure being called is no longer active. Therefore, if +the handler procedure itself throws an exception, that exception can +only be caught by another active catch higher up the call stack, if +there is one. + + +@node Throw +@subsection Throwing Exceptions + +The @code{throw} primitive is used to throw an exception. One argument, +the @var{key}, is mandatory, and must be a symbol; it indicates the type +of exception that is being thrown. Following the @var{key}, +@code{throw} accepts any number of additional arguments, whose meaning +depends on the exception type. The documentation for each possible type +of exception should specify the additional arguments that are expected +for that kind of exception. + +@deffn primitive throw key . args +Invoke the catch form matching @var{key}, passing @var{args} to the +@var{handler}. + +@var{key} is a symbol. It will match catches of the same symbol or of +@code{#t}. + +If there is no handler at all, Guile prints an error and then exits. +@end deffn + +When an exception is thrown, it will be caught by the innermost +@code{catch} expression that applies to the type of the thrown +exception; in other words, the innermost @code{catch} whose @var{key} is +@code{#t} or is the same symbol as that used in the @code{throw} +expression. Once Guile has identified the appropriate @code{catch}, it +handles the exception by applying that @code{catch} expression's handler +procedure to the arguments of the @code{throw}. + +If there is no appropriate @code{catch} for a thrown exception, Guile +prints an error to the current error port indicating an uncaught +exception, and then exits. In practice, it is quite difficult to +observe this behaviour, because Guile when used interactively installs a +top level @code{catch} handler that will catch all exceptions and print +an appropriate error message @emph{without} exiting. For example, this +is what happens if you try to throw an unhandled exception in the +standard Guile REPL; note that Guile's command loop continues after the +error message: + +@lisp +guile> (throw 'badex) +<unnamed port>:3:1: In procedure gsubr-apply @dots{} +<unnamed port>:3:1: unhandled-exception: badex +ABORT: (misc-error) +guile> +@end lisp + +The default uncaught exception behaviour can be observed by evaluating a +@code{throw} expression from the shell command line: + +@example +$ guile -c "(begin (throw 'badex) (display \"here\\n\"))" +guile: uncaught throw to badex: () +$ +@end example + +@noindent +That Guile exits immediately following the uncaught exception +is shown by the absence of any output from the @code{display} +expression, because Guile never gets to the point of evaluating that +expression. + + +@node Lazy Catch +@subsection Catch Without Unwinding + +A @dfn{lazy catch} is used in the same way as a normal @code{catch}, +with @var{key}, @var{thunk} and @var{handler} arguments specifying the +exception type, normal case code and handler procedure, but differs in +one important respect: the handler procedure is executed without +unwinding the call stack from the context of the @code{throw} expression +that caused the handler to be invoked. + +@deffn primitive lazy-catch key thunk handler +This behaves exactly like @code{catch}, except that it does +not unwind the stack before invoking @var{handler}. +The @var{handler} procedure is not allowed to return: +it must throw to another catch, or otherwise exit non-locally. +@end deffn + +Typically, @var{handler} should save any desired state associated with +the stack at the point where the corresponding @code{throw} occurred, +and then throw an exception itself --- usually the same exception as the +one it caught. If @var{handler} is invoked and does @emph{not} throw an +exception, Guile itself throws an exception with key @code{misc-error}. + +Not unwinding the stack means that throwing an exception that is caught +by a @code{lazy-catch} is @emph{almost} equivalent to calling the +@code{lazy-catch}'s handler inline instead of each @code{throw}, and +then omitting the surrounding @code{lazy-catch}. In other words, + +@lisp +(lazy-catch 'key + (lambda () @dots{} (throw 'key args @dots{}) @dots{}) + handler) +@end lisp + +@noindent +is @emph{almost} equivalent to + +@lisp +((lambda () @dots{} (handler 'key args @dots{}) @dots{})) +@end lisp + +@noindent +But why only @emph{almost}? The difference is that with +@code{lazy-catch} (as with normal @code{catch}), the dynamic context is +unwound back to just outside the @code{lazy-catch} expression before +invoking the handler. (For an introduction to what is meant by dynamic +context, @xref{Dynamic Wind}.) + +Then, when the handler @emph{itself} throws an exception, that exception +must be caught by some kind of @code{catch} (including perhaps another +@code{lazy-catch}) higher up the call stack. + +The dynamic context also includes @code{with-fluids} blocks (REFFIXME), +so the effect of unwinding the dynamic context can also be seen in fluid +variable values. This is illustrated by the following code, in which +the normal case thunk uses @code{with-fluids} to temporarily change the +value of a fluid: + +@lisp +(define f (make-fluid)) +(fluid-set! f "top level value") + +(define (handler . args) + (cons (fluid-ref f) args)) + +(lazy-catch 'foo + (lambda () + (with-fluids ((f "local value")) + (throw 'foo))) + handler) +@result{} +("top level value" foo) + +((lambda () + (with-fluids ((f "local value")) + (handler 'foo)))) +@result{} +("local value" foo) +@end lisp + +@noindent +In the @code{lazy-catch} version, the unwinding of dynamic context +restores @code{f} to its value outside the @code{with-fluids} block +before the handler is invoked, so the handler's @code{(fluid-ref f)} +returns the external value. + +@code{lazy-catch} is useful because it permits the implementation of +debuggers and other reflective programming tools that need to access the +state of the call stack at the exact point where an exception or an +error is thrown. For an example of this, see REFFIXME:stack-catch. + + +@node Exception Implementation +@subsection How Guile Implements Exceptions + +It is traditional in Scheme to implement exception systems using +@code{call-with-current-continuation}. Continuations +(@pxref{Continuations}) are such a powerful concept that any other +control mechanism --- including @code{catch} and @code{throw} --- can be +implemented in terms of them. + +Guile does not implement @code{catch} and @code{throw} like this, +though. Why not? Because Guile is specifically designed to be easy to +integrate with applications written in C. In a mixed Scheme/C +environment, the concept of @dfn{continuation} must logically include +``what happens next'' in the C parts of the application as well as the +Scheme parts, and it turns out that the only reasonable way of +implementing continuations like this is to save and restore the complete +C stack. + +So Guile's implementation of @code{call-with-current-continuation} is a +stack copying one. This allows it to interact well with ordinary C +code, but means that creating and calling a continuation is slowed down +by the time that it takes to copy the C stack. + +The more targeted mechanism provided by @code{catch} and @code{throw} +does not need to save and restore the C stack because the @code{throw} +always jumps to a location higher up the stack of the code that executes +the @code{throw}. Therefore Guile implements the @code{catch} and +@code{throw} primitives independently of +@code{call-with-current-continuation}, in a way that takes advantage of +this @emph{upwards only} nature of exceptions. + + +@node Error Reporting +@section Procedures for Signaling Errors + +Guile provides a set of convenience procedures for signaling error +conditions that are implemented on top of the exception primitives just +described. + +@deffn procedure error msg args @dots{} +Raise an error with key @code{misc-error} and a message constructed by +displaying @var{msg} and writing @var{args}. +@end deffn + +@deffn primitive scm-error key subr message args data +Raise an error with key @var{key}. @var{subr} can be a string +naming the procedure associated with the error, or @code{#f}. +@var{message} is the error message string, possibly containing +@code{~S} and @code{~A} escapes. When an error is reported, +these are replaced by formatting the corresponding members of +@var{args}: @code{~A} (was @code{%s} in older versions of +Guile) formats using @code{display} and @code{~S} (was +@code{%S}) formats using @code{write}. @var{data} is a list or +@code{#f} depending on @var{key}: if @var{key} is +@code{system-error} then it should be a list containing the +Unix @code{errno} value; If @var{key} is @code{signal} then it +should be a list containing the Unix signal number; otherwise +it will usually be @code{#f}. +@end deffn + +@deffn primitive strerror err +Return the Unix error message corresponding to @var{err}, which +must be an integer value. +@end deffn + +@c begin (scm-doc-string "boot-9.scm" "false-if-exception") +@deffn syntax false-if-exception expr +Returns the result of evaluating its argument; however +if an exception occurs then @code{#f} is returned instead. +@end deffn +@c end + + +@node Dynamic Wind +@section Dynamic Wind + +[FIXME: this is pasted in from Tom Lord's original guile.texi and should +be reviewed] + +@rnindex dynamic-wind +@deffn primitive dynamic-wind in_guard thunk out_guard +All three arguments must be 0-argument procedures. +@var{in_guard} is called, then @var{thunk}, then +@var{out_guard}. + +If, any time during the execution of @var{thunk}, the +continuation of the @code{dynamic_wind} expression is escaped +non-locally, @var{out_guard} is called. If the continuation of +the dynamic-wind is re-entered, @var{in_guard} is called. Thus +@var{in_guard} and @var{out_guard} may be called any number of +times. +@lisp +(define x 'normal-binding) +@result{} x +(define a-cont (call-with-current-continuation + (lambda (escape) + (let ((old-x x)) + (dynamic-wind + ;; in-guard: + ;; + (lambda () (set! x 'special-binding)) + + ;; thunk + ;; + (lambda () (display x) (newline) + (call-with-current-continuation escape) + (display x) (newline) + x) + + ;; out-guard: + ;; + (lambda () (set! x old-x))))))) + +;; Prints: +special-binding +;; Evaluates to: +@result{} a-cont +x +@result{} normal-binding +(a-cont #f) +;; Prints: +special-binding +;; Evaluates to: +@result{} a-cont ;; the value of the (define a-cont...) +x +@result{} normal-binding +a-cont +@result{} special-binding +@end lisp +@end deffn +@c Local Variables: +@c TeX-master: "guile.texi" +@c End: |