Common Lisp the Language, 2nd Edition
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)))))
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