Common Lisp the Language, 2nd Edition
Conceptually, signaling an error in a program is an admission by that program
that it does not know how to continue and requires external intervention. Once
an error is signaled, any decision about how to continue must come from the
``outside.''
The simplest way to signal an error is to use the error function with format-style arguments describing the error for the sake of the user interface. If error is called and there are no active handlers (described in sections 29.3.2 and 29.3.3), the debugger will be entered and the error message will be typed out. For example:
Lisp> (defun factorial (x) (cond ((or (not (typep x 'integer)) (minusp x)) (error "~S is not a valid argument to FACTORIAL." x)) ((zerop x) 1) (t (* x (factorial (- x 1)))))) => FACTORIAL Lisp> (factorial 20) => 2432902008176640000 Lisp> (factorial -1) Error: -1 is not a valid argument to FACTORIAL. To continue, type :CONTINUE followed by an option number: 1: Return to Lisp Toplevel. Debug>
In general, a call to error cannot directly return. Unless special work has been done to override this behavior, the debugger will be entered and there will be no option to simply continue.
The only exception may be that some implementations may provide debugger commands for interactively returning from individual stack frames; even then, however, such commands should never be used except by someone who has read the erring code and understands the consequences of continuing from that point. In particular, the programmer should feel confident about writing code like this:
(defun wargames:no-win-scenario () (when (true) (error "Pushing the button would be stupid.")) (push-the-button))
In this scenario, there should be no chance that the function error will return and the button will be pushed.
In some cases, the programmer may have a single, well-defined idea of a reasonable recovery strategy for this particular error. In that case, he can use the function cerror, which specifies information about what would happen if the user did simply continue from the call to cerror. For example:
Lisp> (defun factorial (x) (cond ((not (typep x 'integer)) (error "~S is not a valid argument to FACTORIAL." x)) ((minusp x) (let ((x-magnitude (- x))) (cerror "Compute -(~D!) instead." "(-~D)! is not defined." x-magnitude) (- (factorial x-magnitude)))) ((zerop x) 1) (t (* x (factorial (- x 1)))))) => FACTORIAL Lisp> (factorial -3) Error: (-3)! is not defined. To continue, type :CONTINUE followed by an option number: 1: Compute -(3!) instead. 2: Return to Lisp Toplevel. Debug> :continue 1 => -6