Common Lisp the Language, 2nd Edition
restart-case is a mechanism that allows only imperative transfer of control for its associated restarts. restart-case is built on a lower-level mechanism called restart-bind, which does not force transfer of control.
restart-bind is to restart-case as handler-bind is to handler-case. The syntax is
(restart-bind ((name function . options)) . body)
The body is executed in a dynamic context within which the function will be called whenever (invoke-restart 'name) is executed. The options are keyword-style and are used to pass information such as that provided with the :report keyword in restart-case.
A restart-case expands into a call to restart-bind where the function simply does an unconditional transfer of control to a particular body of code, passing along ``argument'' information in a structured way.
It is also possible to write restarts that do not transfer control. Such restarts may be useful in implementing various special commands for the debugger that are of interest only in certain situations. For example, one might imagine a situation where file space was exhausted and the following was done in an attempt to free space in directory dir:
(restart-bind ((nil #'(lambda () (expunge-directory dir)) :report-function #'(lambda (stream) (format stream "Expunge ~A." (directory-namestring dir))))) (cerror "Try this file operation again." 'directory-full :directory dir))
In this case, the debugger might be entered and the user could first perform the expunge (which would not transfer control from the debugger context) and then retry the file operation:
Lisp> (open "FOO" :direction :output) Error: The directory PS:<JDOE> is full. To continue, type :CONTINUE followed by an option number: 1: Try this file operation again. 2: Expunge PS:<JDOE>. 3: Return to Lisp Toplevel. Debug> :continue 2 Expunging PS:<JDOE> ... 3 records freed. Debug> :continue 1 => #<OUTPUT-STREAM "PS:<JDOE>FOO.LSP" 2323473>