diff --git a/doc/ref/scheme-control.texi b/doc/ref/scheme-control.texi index 52aaa0d11..e69de29bb 100644 --- a/doc/ref/scheme-control.texi +++ b/doc/ref/scheme-control.texi @@ -1,1337 +0,0 @@ -@c -*-texinfo-*- -@c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004 -@c Free Software Foundation, Inc. -@c See the file guile.texi for copying conditions. - -@page -@node Control Mechanisms -@section Controlling the Flow of Program Execution - -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. -* 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. -* Frames:: Another way to handle non-localness -* Handling Errors:: How to handle errors in C code. -@end menu - -@node begin -@subsection Evaluating a Sequence of Expressions - -@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: - -@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. - -Guile also allows the expression @code{(begin)}, a @code{begin} with no -sub-expressions. Such an expression returns the `unspecified' value. -@end deffn - -@node if cond case -@subsection Simple Conditional Evaluation - -@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 ignored. 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 symbol @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 expression(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 -@subsection Conditional Evaluation of a Sequence of Expressions - -@code{and} and @code{or} evaluate all their arguments in order, 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 -@subsection Iteration mechanisms - -@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 ((variable init [step]) @dots{}) (test [expr @dots{}]) body @dots{} -Bind @var{variable}s and evaluate @var{body} until @var{test} is true. -The return value is the last @var{expr} after @var{test}, if given. A -simple example will illustrate the basic form, - -@example -(do ((i 1 (1+ i))) - ((> i 4)) - (display i)) -@print{} 1234 -@end example - -@noindent -Or with two variables and a final return value, - -@example -(do ((i 1 (1+ i)) - (p 3 (* 3 p))) - ((> i 4) - p) - (format #t "3**~s is ~s\n" i p)) -@print{} -3**1 is 3 -3**2 is 9 -3**3 is 27 -3**4 is 81 -@result{} -789 -@end example - -The @var{variable} bindings are established like a @code{let}, in that -the expressions are all evaluated and then all bindings made. When -iterating, the optional @var{step} expressions are evaluated with the -previous bindings in scope, then new bindings all made. - -The @var{test} expression is a termination condition. Looping stops -when the @var{test} is true. It's evaluated before running the -@var{body} each time, so if it's true the first time then @var{body} -is not run at all. - -The optional @var{expr}s after the @var{test} are evaluated at the end -of looping, with the final @var{variable} bindings available. The -last @var{expr} gives the return value, or if there are no @var{expr}s -the return value is unspecified. - -Each iteration establishes bindings to fresh locations for the -@var{variable}s, like a new @code{let} for each iteration. This is -done for @var{variable}s without @var{step} expressions too. The -following illustrates this, showing how a new @code{i} is captured by -the @code{lambda} in each iteration (@pxref{About Closure,, The -Concept of Closure}). - -@example -(define lst '()) -(do ((i 1 (1+ i))) - ((> i 4)) - (set! lst (cons (lambda () i) lst))) -(map (lambda (proc) (proc)) lst) -@result{} -(4 3 2 1) -@end example -@end deffn - -@deffn syntax while cond body @dots{} -Run a loop executing the @var{body} forms while @var{cond} is true. -@var{cond} is tested at the start of each iteration, so if it's -@code{#f} the first time then @var{body} is not executed at all. The -return value is unspecified. - -Within @code{while}, two extra bindings are provided, they can be used -from both @var{cond} and @var{body}. - -@deffn {Scheme Procedure} break -Break out of the @code{while} form. -@end deffn - -@deffn {Scheme Procedure} continue -Abandon the current iteration, go back to the start and test -@var{cond} again, etc. -@end deffn - -Each @code{while} form gets its own @code{break} and @code{continue} -procedures, operating on that @code{while}. This means when loops are -nested the outer @code{break} can be used to escape all the way out. -For example, - -@example -(while (test1) - (let ((outer-break break)) - (while (test2) - (if (something) - (outer-break #f)) - ...))) -@end example - -Note that each @code{break} and @code{continue} procedure can only be -used within the dynamic extent of its @code{while}. Outside the -@code{while} their behaviour is unspecified. -@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 -@subsection Continuations -@cindex continuations - -A ``continuation'' is the code that will execute when a given function -or expression returns. For example, consider - -@example -(define (foo) - (display "hello\n") - (display (bar)) (newline) - (exit)) -@end example - -The continuation from the call to @code{bar} comprises a -@code{display} of the value returned, a @code{newline} and an -@code{exit}. This can be expressed as a function of one argument. - -@example -(lambda (r) - (display r) (newline) - (exit)) -@end example - -In Scheme, continuations are represented as special procedures just -like this. The special property is that when a continuation is called -it abandons the current program location and jumps directly to that -represented by the continuation. - -A continuation is like a dynamic label, capturing at run-time a point -in program execution, including all the nested calls that have lead to -it (or rather the code that will execute when those calls return). - -Continuations are created with the following functions. - -@deffn {Scheme Procedure} call-with-current-continuation proc -@deffnx {Scheme Procedure} call/cc proc -@rnindex call-with-current-continuation -Capture the current continuation and call @code{(@var{proc} -@var{cont})} with it. The return value is the value returned by -@var{proc}, or when @code{(@var{cont} @var{value})} is later invoked, -the return is the @var{value} passed. - -Normally @var{cont} should be called with one argument, but when the -location resumed is expecting multiple values (@pxref{Multiple -Values}) then they should be passed as multiple arguments, for -instance @code{(@var{cont} @var{x} @var{y} @var{z})}. - -@var{cont} may only be used from the dynamic root in which it was -created (@pxref{Dynamic Roots}), and in a multi-threaded program only -from the thread in which it was created, since each thread is a -separate dynamic root. - -The call to @var{proc} is not part of the continuation captured, it runs -only when the continuation is created. Often a program will want to -store @var{cont} somewhere for later use; this can be done in -@var{proc}. - -The @code{call} in the name @code{call-with-current-continuation} -refers to the way a call to @var{proc} gives the newly created -continuation. It's not related to the way a call is used later to -invoke that continuation. - -@code{call/cc} is an alias for @code{call-with-current-continuation}. -This is in common use since the latter is rather long. -@end deffn - -@deftypefn {C Function} SCM scm_make_continuation (int *first) -Capture the current continuation as described above. The return value -is the new continuation, and @var{*first} is set to 1. - -When the continuation is invoked, @code{scm_make_continuation} will -return again, this time returning the value (or set of multiple -values) passed in that invocation, and with @var{*first} set to 0. -@end deftypefn - -@sp 1 -@noindent -Here is a simple example, - -@example -(define kont #f) -(format #t "the return is ~a\n" - (call/cc (lambda (k) - (set! kont k) - 1))) -@result{} the return is 1 - -(kont 2) -@result{} the return is 2 -@end example - -@code{call/cc} captures a continuation in which the value returned is -going to be displayed by @code{format}. The @code{lambda} stores this -in @code{kont} and gives an initial return @code{1} which is -displayed. The later invocation of @code{kont} resumes the captured -point, but this time returning @code{2}, which is displayed. - -When Guile is run interactively, a call to @code{format} like this has -an implicit return back to the read-eval-print loop. @code{call/cc} -captures that like any other return, which is why interactively -@code{kont} will come back to read more input. - -@sp 1 -C programmers may note that @code{call/cc} is like @code{setjmp} in -the way it records at runtime a point in program execution. A call to -a continuation is like a @code{longjmp} in that it abandons the -present location and goes to the recorded one. Like @code{longjmp}, -the value passed to the continuation is the value returned by -@code{call/cc} on resuming there. However @code{longjmp} can only go -up the program stack, but the continuation mechanism can go anywhere. - -When a continuation is invoked, @code{call/cc} and subsequent code -effectively ``returns'' a second time. It can be confusing to imagine -a function returning more times than it was called. It may help -instead to think of it being stealthily re-entered and then program -flow going on as normal. - -@code{dynamic-wind} (@pxref{Dynamic Wind}) can be used to ensure setup -and cleanup code is run when a program locus is resumed or abandoned -through the continuation mechanism. C code can use @dfn{frames} -(@pxref{Frames}). - -@sp 1 -Continuations are a powerful mechanism, and can be used to implement -almost any sort of control structure, such as loops, coroutines, or -exception handlers. - -However the implementation of continuations in Guile is not as -efficient as one might hope, because Guile is designed to cooperate -with programs written in other languages, such as C, which do not know -about continuations. Basically continuations are captured by a block -copy of the stack, and resumed by copying back. - -For this reason, generally continuations should be used only when -there is no other simple way to achieve the desired result, or when -the elegance of the continuation mechanism outweighs the need for -performance. - -Escapes upwards from loops or nested functions are generally best -handled with exceptions (@pxref{Exceptions}). Coroutines can be -efficiently implemented with cooperating threads (a thread holds a -full program stack but doesn't copy it around the way continuations -do). - - -@node Multiple Values -@subsection Returning and Accepting Multiple Values - -@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 -conceptually 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 {Scheme Procedure} values arg1 @dots{} argN -@deffnx {C Function} scm_values (args) -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. - -For @code{scm_values}, @var{args} is a list of arguments and the -return is a multiple-values object which the caller can return. In -the current implementation that object shares structure with -@var{args}, so @var{args} should not be modified subsequently. -@end deffn - -@rnindex call-with-values -@deffn {Scheme Procedure} 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)) -@result{} 5 - -@end example -@example -(call-with-values * -) -@result{} -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 -@subsection 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 -@subsubsection 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. - -This manual prefers to speak of throwing and catching exceptions, since -this terminology matches the corresponding Guile primitives. - - -@node Catch -@subsubsection 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 code to execute and a @dfn{handler} procedure -that says what to do if an exception is thrown while executing the code. -Note that if the execution thunk executes @dfn{normally}, which means -without throwing any exceptions, the handler procedure is not called at -all. - -When an exception is thrown using the @code{throw} function, 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 {Scheme Procedure} catch key thunk handler -@deffnx {C Function} scm_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. - -@sp 1 -@deftypefn {C Function} SCM scm_internal_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data) -The above @code{scm_catch} takes Scheme procedures as body and handler -arguments. @code{scm_internal_catch} is an equivalent taking C -functions. - -@var{body} is called as @code{@var{body} (@var{body_data})} with a -catch on exceptions of the given @var{tag} type. If an exception is -caught, @var{handler} is called @code{@var{handler} -(@var{handler_data}, @var{key}, @var{args})}. @var{key} and -@var{args} are the @code{SCM} key and argument list from the -@code{throw}. - -@tpindex scm_t_catch_body -@tpindex scm_t_catch_handler -@var{body} and @var{handler} should have the following prototypes. -@code{scm_t_catch_body} and @code{scm_t_catch_handler} are pointer -typedefs for these. - -@example -SCM body (void *data); -SCM handler (void *data, SCM key, SCM args); -@end example - -The @var{body_data} and @var{handler_data} parameters are passed to -the respective calls so an application can communicate extra -information to those functions. - -If the data consists of an @code{SCM} object, care should be taken -that it isn't garbage collected while still required. If the -@code{SCM} is a local C variable, one way to protect it is to pass a -pointer to that variable as the data parameter, since the C compiler -will then know the value must be held on the stack. Another way is to -use @code{scm_remember_upto_here_1} (@pxref{Remembering During -Operations}). -@end deftypefn - - -@node Throw -@subsubsection 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 {Scheme Procedure} throw key . args -@deffnx {C Function} scm_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) -:3:1: In procedure gsubr-apply @dots{} -: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 -@subsubsection 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 {Scheme Procedure} lazy-catch key thunk handler -@deffnx {C Function} scm_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 - -@deftypefn {C Function} SCM scm_internal_lazy_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data) -The above @code{scm_lazy_catch} takes Scheme procedures as body and -handler arguments. @code{scm_internal_lazy_catch} is an equivalent -taking C functions. See @code{scm_internal_catch} (@pxref{Catch}) for -a description of the parameters, the behaviour however of course -follows @code{lazy-catch}. -@end deftypefn - -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 -@subsubsection 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 -@subsection 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 {Scheme 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 {Scheme Procedure} scm-error key subr message args data -@deffnx {C Function} scm_error_scm (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 {Scheme Procedure} strerror err -@deffnx {C Function} scm_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 -@subsection Dynamic Wind - -@rnindex dynamic-wind -@deffn {Scheme Procedure} dynamic-wind in_guard thunk out_guard -@deffnx {C Function} scm_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 -dynamic extent of the @code{dynamic-wind} expression is escaped -non-locally, @var{out_guard} is called. If the dynamic extent 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 - -@node Frames -@subsection Frames - -For Scheme code, the fundamental procedure to react to non-local entry -and exits of dynamic contexts is @code{dynamic-wind}. C code could use -@code{scm_internal_dynamic_wind}, but since C does not allow the -convenient construction of anonymous procedures that close over lexical -variables, this will be, well, inconvenient. Instead, C code can use -@dfn{frames}. - -Guile offers the functions @code{scm_frame_begin} and -@code{scm_frame_end} to delimit a dynamic extent. Within this dynamic -extent, which is called a @dfn{frame}, you can perform various -@dfn{frame actions} that control what happens when the frame is entered -or left. For example, you can register a cleanup routine with -@code{scm_frame_unwind} that is executed when the frame is left. There are -several other more specialized frame actions as well, for example to -temporarily block the execution of asyncs or to temporarily change the -current output port. They are described elsewhere in this manual. - -Here is an example that shows how to prevent memory leaks. - -@example - -/* Suppose there is a function called FOO in some library that you - would like to make available to Scheme code (or to C code that - follows the Scheme conventions). - - FOO takes two C strings and returns a new string. When an error has - occurred in FOO, it returns NULL. -*/ - -char *foo (char *s1, char *s2); - -/* SCM_FOO interfaces the C function FOO to the Scheme way of life. - It takes care to free up all temporary strings in the case of - non-local exits. - - It uses SCM_TO_STRING as a helper procedure. - */ - -char * -scm_to_string (SCM obj) -@{ - if (SCM_STRINGP (obj)) - @{ - char *res = scm_malloc (SCM_STRING_LENGTH (obj)+1); - strcpy (res, SCM_STRING_CHARS (obj)); - scm_remember_upto_here_1 (obj); - return res; - @} - else - scm_wrong_type_arg ("scm_to_string", 1, obj); -@} - -SCM -scm_foo (SCM s1, SCM s2) -@{ - char *c_s1, *c_s2, *c_res; - - scm_frame_begin (0); - - c_s1 = scm_to_string (s1); - scm_frame_unwind_handler (free, c_s1, SCM_F_WIND_EXPLICITLY); - - c_s2 = scm_to_string (s2); - scm_frame_unwind_handler (free, c_s2, SCM_F_WIND_EXPLICITLY); - - c_res = foo (c_s1, c_s2); - if (c_res == NULL) - scm_memory_error ("foo"); - - scm_frame_end (); - - return scm_take0str (res); -@} -@end example - -@deftp {C Type} scm_t_frame_flags -This is an enumeration of several flags that modify the behavior of -@code{scm_begin_frame}. The flags are listed in the following table. - -@table @code -@item SCM_F_FRAME_REWINDABLE -The frame is @dfn{rewindable}. This means that it can be reentered -non-locally (via the invokation of a continuation). The default is that -a frame can not be reentered non-locally. -@end table - -@end deftp - -@deftypefn {C Function} void scm_frame_begin (scm_t_frame_flags flags) -The function @code{scm_begin_frame} starts a new frame and makes it the -`current' one. - -The @var{flags} argument determines the default behavior of the frame. -For normal frames, use 0. This will result in a frame that can not be -reentered with a captured continuation. When you are prepared to handle -reentries, include @code{SCM_F_FRAME_REWINDABLE} in @var{flags}. - -Being prepared for reentry means that the effects of unwind handlers -can be undone on reentry. In the example above, we want to prevent a -memory leak on non-local exit and thus register an unwind handler that -frees the memory. But once the memory is freed, we can not get it -back on reentry. Thus reentry can not be allowed. - -The consequence is that continuations become less useful when -non-reenterable frames are captured, but you don't need to worry about -that too much. - -The frame is ended either implicitly when a non-local exit happens, or -explicitly with @code{scm_end_frame}. You must make sure that a frame -is indeed ended properly. If you fail to call @code{scm_end_frame} -for each @code{scm_begin_frame}, the behavior is undefined. -@end deftypefn - -@deftypefn {C Function} void scm_frame_end () -End the current frame explicitly and make the previous frame current. -@end deftypefn - -@deftp {C Type} scm_t_wind_flags -This is an enumeration of several flags that modify the behavior of -@code{scm_on_unwind_handler} and @code{scm_on_rewind_handler}. The -flags are listed in the following table. - -@table @code -@item SCM_F_WIND_EXPLICITLY -@findex SCM_F_WIND_EXPLICITLY -The registered action is also carried out when the frame is entered or -left locally. -@end table -@end deftp - -@deftypefn {C Function} void scm_frame_unwind_handler (void (*func)(void *), void *data, scm_t_wind_flags flags) -@deftypefnx {C Function} void scm_frame_unwind_handler_with_scm (void (*func)(SCM), SCM data, scm_t_wind_flags flags) -Arranges for @var{func} to be called with @var{data} as its arguments -when the current frame ends implicitly. If @var{flags} contains -@code{SCM_F_WIND_EXPLICITLY}, @var{func} is also called when the frame -ends explicitly with @code{scm_frame_end}. - -The function @code{scm_frame_unwind_handler_with_scm} takes care that -@var{data} is protected from garbage collection. -@end deftypefn - -@deftypefn {C Function} void scm_frame_rewind_handler (void (*func)(void *), void *data, scm_t_wind_flags flags) -@deftypefnx {C Function} void scm_frame_rewind_handler_with_scm (void (*func)(SCM), SCM data, scm_t_wind_flags flags) -Arrange for @var{func} to be called with @var{data} as its argument when -the current frame is restarted by rewinding the stack. When @var{flags} -contains @code{SCM_F_WIND_EXPLICITLY}, @var{func} is called immediately -as well. - -The function @code{scm_frame_rewind_handler_with_scm} takes care that -@var{data} is protected from garbage collection. -@end deftypefn - - -@node Handling Errors -@subsection How to Handle Errors - -Error handling is based on @code{catch} and @code{throw}. Errors are -always thrown with a @var{key} and four arguments: - -@itemize @bullet -@item -@var{key}: a symbol which indicates the type of error. The symbols used -by libguile are listed below. - -@item -@var{subr}: the name of the procedure from which the error is thrown, or -@code{#f}. - -@item -@var{message}: a string (possibly language and system dependent) -describing the error. The tokens @code{~A} and @code{~S} can be -embedded within the message: they will be replaced with members of the -@var{args} list when the message is printed. @code{~A} indicates an -argument printed using @code{display}, while @code{~S} indicates an -argument printed using @code{write}. @var{message} can also be -@code{#f}, to allow it to be derived from the @var{key} by the error -handler (may be useful if the @var{key} is to be thrown from both C and -Scheme). - -@item -@var{args}: a list of arguments to be used to expand @code{~A} and -@code{~S} tokens in @var{message}. Can also be @code{#f} if no -arguments are required. - -@item -@var{rest}: a list of any additional objects required. e.g., when the -key is @code{'system-error}, this contains the C errno value. Can also -be @code{#f} if no additional objects are required. -@end itemize - -In addition to @code{catch} and @code{throw}, the following Scheme -facilities are available: - -@deffn {Scheme Procedure} display-error stack port subr message args rest -@deffnx {C Function} scm_display_error (stack, port, subr, message, args, rest) -Display an error message to the output port @var{port}. -@var{stack} is the saved stack for the error, @var{subr} is -the name of the procedure in which the error occurred and -@var{message} is the actual error message, which may contain -formatting instructions. These will format the arguments in -the list @var{args} accordingly. @var{rest} is currently -ignored. -@end deffn - -The following are the error keys defined by libguile and the situations -in which they are used: - -@itemize @bullet -@item -@cindex @code{error-signal} -@code{error-signal}: thrown after receiving an unhandled fatal signal -such as SIGSEGV, SIGBUS, SIGFPE etc. The @var{rest} argument in the throw -contains the coded signal number (at present this is not the same as the -usual Unix signal number). - -@item -@cindex @code{system-error} -@code{system-error}: thrown after the operating system indicates an -error condition. The @var{rest} argument in the throw contains the -errno value. - -@item -@cindex @code{numerical-overflow} -@code{numerical-overflow}: numerical overflow. - -@item -@cindex @code{out-of-range} -@code{out-of-range}: the arguments to a procedure do not fall within the -accepted domain. - -@item -@cindex @code{wrong-type-arg} -@code{wrong-type-arg}: an argument to a procedure has the wrong type. - -@item -@cindex @code{wrong-number-of-args} -@code{wrong-number-of-args}: a procedure was called with the wrong number -of arguments. - -@item -@cindex @code{memory-allocation-error} -@code{memory-allocation-error}: memory allocation error. - -@item -@cindex @code{stack-overflow} -@code{stack-overflow}: stack overflow error. - -@item -@cindex @code{regular-expression-syntax} -@code{regular-expression-syntax}: errors generated by the regular -expression library. - -@item -@cindex @code{misc-error} -@code{misc-error}: other errors. -@end itemize - - -@subsubsection C Support - -In the following C functions, @var{SUBR} and @var{MESSAGE} parameters -can be @code{NULL} to give the effect of @code{#f} described above. - -@deftypefn {C Function} SCM scm_error (SCM @var{key}, char *@var{subr}, char *@var{message}, SCM @var{args}, SCM @var{rest}) -Throw an error, as per @code{scm-error} above. -@end deftypefn - -@deftypefn {C Function} void scm_syserror (char *@var{subr}) -@deftypefnx {C Function} void scm_syserror_msg (char *@var{subr}, char *@var{message}, SCM @var{args}) -Throw an error with key @code{system-error} and supply @code{errno} in -the @var{rest} argument. For @code{scm_syserror} the message is -generated using @code{strerror}. - -Care should be taken that any code in between the failing operation -and the call to these routines doesn't change @code{errno}. -@end deftypefn - -@deftypefn {C Function} void scm_num_overflow (char *@var{subr}) -@deftypefnx {C Function} void scm_out_of_range (char *@var{subr}, SCM @var{bad_value}) -@deftypefnx {C Function} void scm_wrong_num_args (SCM @var{proc}) -@deftypefnx {C Function} void scm_wrong_type_arg (char *@var{subr}, int @var{argnum}, SCM @var{bad_value}) -@deftypefnx {C Function} void scm_memory_error (char *@var{subr}) -Throw an error with the various keys described above. - -For @code{scm_wrong_num_args}, @var{proc} should be a Scheme symbol -which is the name of the procedure incorrectly invoked. -@end deftypefn - - -@c Local Variables: -@c TeX-master: "guile.texi" -@c End: