Common Lisp the Language, 2nd Edition
Next: Named Restarts
Up: Survey of Concepts
Previous: Restarts
The simplest kind of restart involves structured transfer of control
using a macro called restart-case
. The
restart-case
form allows execution of a piece of code in a
context where zero or more restarts are active, and where if one of
those restarts is ``invoked,’’ control will be transferred to the
corresponding clause in the restart-case
form. For example,
we could rewrite the previous divide
example as
follows.
(defun divide (numerator denominator)
(loop
(restart-case
(return
(cond ((or (not (numberp numerator))
(not (numberp denominator)))
(error "(DIVIDE '~S '~S) - Bad arguments."
numerator denominator))
((zerop denominator)
(error 'division-by-zero
:operator 'divide
:operands (list numerator denominator)))
(t ...)))
(nil (arg1 arg2)
:report "Provide new arguments for use by DIVIDE."
:interactive
(lambda ()
(list (prompt-for 'number "Numerator: ")
(prompt-for 'number "Denominator: ")))
(setq numerator arg1 denominator arg2))
(nil (result)
:report "Provide a value to return from DIVIDE."
:interactive
(lambda () (list (prompt-for 'number "Result: ")))
(return result)))))
Remark: The function prompt-for
used in
this chapter in a number of places is not a part of Common Lisp. It is
used in the examples in this chapter only to keep the presentation
simple. It is assumed to accept a type specifier and optionally a format
string and associated arguments. It uses the format string and
associated arguments as part of an interactive prompt, and uses
read
to read a Lisp object; however, only an object of the
type indicated by the type specifier is accepted.
The question of whether or not prompt-for
(or something
like it) would be a useful addition to Common Lisp is under
consideration by X3J13, but as of January 1989 no action has been taken.
In spite of its use in a number of examples, nothing in the Common Lisp
Condition System depends on this function.
In the example, the nil
at the head of each clause means
that it is an ``anonymous’’ restart. Anonymous restarts are typically
invoked only from within the debugger. As we shall see later, it is
possible to have ``named restarts’’ that may be invoked from code
without the need for user intervention.
If the arguments to anonymous restarts are not optional, then special
information must be provided about what the debugger should use as
arguments. Here the :interactive
keyword is used to specify
that information.
The :report
keyword introduces information to be used
when presenting the restart option to the user (by the debugger, for
example).
Here is a sample interaction that takes advantage of the restarts
provided by the revised definition of divide
:
Lisp> (+ (divide 3 0) 7)
Error: Attempt to divide 3 by 0.
To continue, type :CONTINUE followed by an option number:
1: Provide new arguments for use by the DIVIDE function.
2: Provide a value to return from the DIVIDE function.
3: Return to Lisp Toplevel.
Debug> :continue 1
1
Numerator: 4
Denominator: 2
=> 9
Next: Named Restarts
Up: Survey of Concepts
Previous: Restarts
AI.Repository@cs.cmu.edu