Common Lisp the Language, 2nd Edition
Next: Defining Conditions
Up: Program Interface to
Previous: Exhaustive Case
Analysis
These macros allow a program to gain control when a condition is
signaled.
[Macro]
handler-case
expression
{(
typespec
([
var
]) {
form
}*)}*
Executes the given expression in a context where various specified handlers are active.
Each typespec may be any type specifier. If during the
execution of the expression
a condition is signaled for
which there is an appropriate clause-that is, one for which
(typep
condition
'
typespec
)
is true-and if there is no intervening handler for conditions of that
type, then control is transferred to the body of the relevant clause
(unwinding the dynamic state appropriately in the process) and the given
variable var
is bound to the condition that was signaled.
If no such condition is signaled and the computation runs to completion,
then the values resulting from the expression
are returned
by the handler-case
form.
If more than one case is provided, those cases are made accessible in parallel. That is, in
(handler-case expression
(type1 (var1) form1)
(type2 (var2) form2))
if the first clause (containing form1) has been selected, the handler for the second is no longer visible (and vice versa).
The cases are searched sequentially from top to bottom. If a signaled condition matches more than one case (possible if there is type overlap) the earlier of the two cases will be selected.
If the variable var is not needed, it may be omitted. That is, a clause such as
(type (var) (declare (ignore var)) form)
may be written using the following shorthand notation:
(type () form)
If there are no forms in a selected case, the case returns
nil
. Note that
(handler-case expression
(type1 (var1) . body1)
(type2 (var2) . body2)
...)
is approximately equivalent to
(block #1=#:block-1
(let (#2=#:var-2)
(tagbody
(handler-bind ((type1 ¯#'(lambda (temp)
(setq #2# temp)
(go #3=#:tag-3)))
(type2 ¯#'(lambda (temp)
(setq #2# temp)
(go #4=#:tag-4)))
...)
(return-from #1# expression))
#3# (return-from #1# (let ((var1 #2#)) . body1))
#4# (return-from #1# (let ((var2 #2#)) . body2))
...)))
[Note the use of ``gensyms’’ such as #:block-1
as block
names, variables, and tagbody
tags in this example, and the
use of #
n
=
and
#
n
#
read-macro syntax to
indicate that the very same gensym appears in multiple places.-GLS]
As a special case, the typespec can also be the symbol
:no-error
in the last clause. If it is, it designates a
clause that will take control if the expression returns
normally. In that case, a completely general lambda-list may follow the
symbol :no-error
, and the arguments to which the
lambda-list parameters are bound are like those for
multiple-value-call
on the return value of the
expression. For example,
(handler-case expression
(type1 (var1) . body1)
(type2 (var2) . body2)
...
(typen (varn) . bodyn)
(:no-error (nvar1 nvar2 ... nvarm) . nbody))
is approximately equivalent to
(block #1=#:error-return
(multiple-value-call #'(lambda (nvar1 nvar2 ... nvarm) . nbody)
(block #2=#:normal-return
(return-from #1#
(handler-case (return-from #2# expression)
(type1 (var1) . body1)
(type2 (var2) . body2)
...
(typen (varn) . bodyn))))))
Examples of the use of handler-case
:
(handler-case (/ x y)
(division-by-zero () nil))
(handler-case (open *the-file* :direction :input)
(file-error (condition) (format t "~&Fooey: ~A~%" condition)))
(handler-case (some-user-function)
(file-error (condition) condition)
(division-by-zero () 0)
((or unbound-variable undefined-function) () 'unbound))
(handler-case (intern x y)
(error (condition) condition)
(:no-error (symbol status)
(declare (ignore symbol))
status))
[Macro]
ignore-errors {
form
}*
Executes its body in a context that handles conditions of type
error
by returning control to this form. If no such
condition is signaled, any values returned by the last form are returned
by ignore-errors
. Otherwise, two values are returned:
nil
and the error
condition that was
signaled.
ignore-errors
could be defined by
(defmacro ignore-errors (&body forms)
`(handler-case (progn ,@forms)
(error (c) (values nil c)))
[Macro]
handler-bind ({(
typespec
handler
)}*) {
form
}*
Executes body in a dynamic context where the given handler bindings are in effect. Each typespec may be any type specifier. Each handler form should evaluate to a function to be used to handle conditions of the given type(s) during execution of the forms. This function should take a single argument, the condition being signaled.
If more than one binding is specified, the bindings are searched
sequentially from top to bottom in search of a match (by visual analogy
with typecase
). If an appropriate typespec is
found, the associated handler is run in a context where none of the
handler bindings are visible (to avoid recursive errors). For example,
in the case of
(handler-bind ((unbound-variable #'(lambda ...))
(error #'(lambda ...)))
...)
if an unbound variable error is signaled in the body (and not handled
by an intervening handler), the first function will be called. If any
other kind of error is signaled, the second function will be called. In
either case, neither handler will be active while executing the code in
the associated function.
Next: Defining Conditions
Up: Program Interface to
Previous: Exhaustive Case
Analysis
AI.Repository@cs.cmu.edu