mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-01 12:20:26 +02:00
* Doc updates for lazy-catch and IP address conversion
This commit is contained in:
parent
e2b6ddc668
commit
7215d65eb2
3 changed files with 22 additions and 849 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2001-05-19 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* posix.texi (Networking): Split existing material into new nodes
|
||||||
|
`Network Address Conversion' and `Network Databases'.
|
||||||
|
|
||||||
|
* scheme-control.texi (Lazy Catch): Update doc for new constraint
|
||||||
|
that lazy-catch handlers are not allowed to return.
|
||||||
|
|
||||||
2001-05-16 Neil Jerram <neil@ossau.uklinux.net>
|
2001-05-16 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
* data-rep.texi, srfi-modules.texi (SRFI-14 Iterating Over
|
* data-rep.texi, srfi-modules.texi (SRFI-14 Iterating Over
|
||||||
|
|
|
@ -1542,18 +1542,18 @@ close a pipe, but doesn't return the status.
|
||||||
@section Networking
|
@section Networking
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Network Databases and Address Conversion::
|
* Network Address Conversion::
|
||||||
|
* Network Databases::
|
||||||
* Network Sockets and Communication::
|
* Network Sockets and Communication::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Network Databases and Address Conversion
|
@node Network Address Conversion
|
||||||
@subsection Network Databases and Address Conversion
|
@subsection Network Address Conversion
|
||||||
|
|
||||||
This section describes procedures which convert internet addresses
|
This section describes procedures which convert internet addresses
|
||||||
and query various network databases. Care should be taken when using
|
between numeric and string formats.
|
||||||
the database routines since they are not reentrant.
|
|
||||||
|
|
||||||
@subsubsection Address Conversion
|
@subsubsection IPv4 Address Conversion
|
||||||
|
|
||||||
@deffn primitive inet-aton address
|
@deffn primitive inet-aton address
|
||||||
Convert an IPv4 Internet address from printable string
|
Convert an IPv4 Internet address from printable string
|
||||||
|
@ -1630,6 +1630,14 @@ the result is an integer with normal host byte ordering.
|
||||||
@end lisp
|
@end lisp
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
|
||||||
|
@node Network Databases
|
||||||
|
@subsection Network Databases
|
||||||
|
|
||||||
|
This section describes procedures which query various network databases.
|
||||||
|
Care should be taken when using the database routines since they are not
|
||||||
|
reentrant.
|
||||||
|
|
||||||
@subsubsection The Host Database
|
@subsubsection The Host Database
|
||||||
|
|
||||||
A @dfn{host object} is a structure that represents what is known about a
|
A @dfn{host object} is a structure that represents what is known about a
|
||||||
|
|
|
@ -1,843 +0,0 @@
|
||||||
@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
|
|
||||||
two important respects.
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
|
||||||
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.
|
|
||||||
|
|
||||||
@item
|
|
||||||
If the handler returns normally --- i.e. does not @emph{itself} throw an
|
|
||||||
exception --- then the @code{throw} expression returns normally to its
|
|
||||||
caller with the handler's value.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@deffn primitive lazy-catch key thunk handler
|
|
||||||
This behaves exactly like @code{catch}, except that it does
|
|
||||||
not unwind the stack (this is the major difference), and if
|
|
||||||
handler returns, its value is returned from the throw.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
The net result is 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}, 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, if 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. On the other hand, if the
|
|
||||||
handler returns normally, the dynamic context is wound back to that of
|
|
||||||
the @code{throw} expression before passing the handler's return value to
|
|
||||||
the continuation of the @code{throw}.
|
|
||||||
|
|
||||||
In most cases where @code{lazy-catch} is used, the handler does indeed
|
|
||||||
throw another exception, which is caught by a higher-level @code{catch}.
|
|
||||||
But this pattern is not mandatory, and it can be useful for the handler
|
|
||||||
to return normally. In the following example, the @code{lazy-catch}
|
|
||||||
handler is called twice and the results of the two calls added together.
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
(lazy-catch 'foo
|
|
||||||
(lambda ()
|
|
||||||
(+ (throw 'foo 1)
|
|
||||||
(throw 'foo 2)))
|
|
||||||
(lambda args
|
|
||||||
(cadr args)))
|
|
||||||
@result{}
|
|
||||||
3
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
To see the point about dynamic context, consider the case where the
|
|
||||||
normal case thunk uses @code{with-fluids} (REFFIXME) 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:
|
|
Loading…
Add table
Add a link
Reference in a new issue