Next: restarts restart-case, Previous: restarts ignore-errors, Up: restarts [Index]
Evaluate body forms in a dynamic environment in which new exception
handlers are installed; it is capable of handling exceptions raised with
raise
, raise-continuable
and signal
. Not quite
like R6RS’s with-exception-handler
syntax, but similar.
The arguments ?clause must have the following syntax:
(?typespec ?condition-handler)
Every ?typespec is meant to be a logic predicate with the format:
?typespec = (?tag) | (and ?inner-pred0 ?inner-pred ...) | (or ?inner-pred0 ?inner-pred ...) | (xor ?inner-pred0 ?inner-pred ...) | (not ?inner-pred) ?inner-pred = ?tag | (and ?inner-pred0 ?inner-pred ...) | (or ?inner-pred0 ?inner-pred ...) | (xor ?inner-pred0 ?inner-pred ...) | (not ?inner-pred)
where: each ?tag is an identifier usable as second argument to
is-a?
; and
, or
, xor
, not
are the identifiers exported by (vicare)
.
Every ?condition-handler must be an expression evaluating to a procedure accepting a condition object as single argument; the condition object can be simple or compound.
If the body performs a normal return: the values returned by the body
become the values returned by handler-bind
.
If an exception is raised (in Common Lisp jargon: a condition is signalled): a condition handler matching the raised object is searched in the sequence of clauses, left–to–right:
raise-continuable
.
The handlers are called with a continuation whose dynamic environment is
that of the call to raise
, raise-continuable
or
signal
that raised the exception; except that the current
exception handler is the one that was in place when
handler-bind
was evaluated.
When a condition handler is applied to the raised condition object:
raise-continuable
.
Usage examples on handling raised conditions:
(import (vicare) (only (vicare checks) with-result add-result)) ;;no condition (with-result (handler-bind ((&error (lambda (E) (add-result 'error-handler) 1)) (&warning (lambda (E) (add-result 'warning-handler) 2))) (add-result 'body) 1)) ⇒ (1 (body)) ;;; ;;Escaping from handler, which is the normal way of accepting ;;to handle a condition. ;; (with-result (call/cc (lambda (escape) (handler-bind ((&error (lambda (E) (add-result 'error-handler) (escape 2)))) (add-result 'body-begin) (signal (make-error)) (add-result 'body-return) 1)))) ⇒ (2 (body-begin error-handler)) ;;The first handler declines to handle a raised exception, ;;the second one accepts. ;; (with-result (call/cc (lambda (escape) (handler-bind ((&warning (lambda (E) ;;By returning this handler declines. (add-result 'warning-handler))) (&error (lambda (E) (add-result 'error-handler) (escape 2)))) (add-result 'body-begin) (raise (condition (make-error) (make-warning))) (add-result 'body-return) 1)))) ⇒ (2 (body-begin warning-handler error-handler)) ;;Multiple condition identifiers in the same clause. ;; (with-result (call/cc (lambda (escape) (handler-bind (((&warning &error) (lambda (E) (add-result 'handler) (escape 2)))) (add-result 'body-begin) (signal (make-error)) (add-result 'body-return) 1)))) ⇒ (2 (body-begin handler)) ;;Nested HANDLER-BIND uses, returning from handler. ;; (with-result (call/cc (lambda (escape) (handler-bind ((&error (lambda (E) (add-result 'outer-error-handler) (escape 2)))) (handler-bind ((&error (lambda (E) (add-result 'inner-error-handler)))) (add-result 'body-begin) (raise (make-error)) (add-result 'body-return) 1))))) ⇒ (2 (body-begin inner-error-handler outer-error-handler)) ;;; unwind-protect (internal-body (define (doit C) (with-result (returnable (handler-bind ((&error (lambda (E) (add-result 'error-handler) (return 1)))) (with-unwind-handler (lambda (why) (add-result 'outer-unwind-handler)) (lambda () (handler-bind ((&warning (lambda (E) (add-result 'warning-handler) (return 2)))) (with-unwind-handler (lambda (why) (add-result 'inner-unwind-handler)) (lambda () (add-result 'body-begin) (signal C) (add-result 'body-normal-return)))))))))) (doit (make-error)) ⇒ (1 (body-begin error-handler inner-unwind-handler outer-unwind-handler)) (doit (make-warning)) ⇒ (2 (body-begin warning-handler inner-unwind-handler outer-unwind-handler)) #| end of body |# )
Usage examples on invoking restarts:
(import (vicare) (only (vicare checks) with-result add-result)) ;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition, ;;call a handler, invoke a restart. ;; (internal-body (define (restarts-outside/handlers-inside C) (with-result (restart-case (handler-bind ((&error (lambda (E) (add-result 'error-handler-begin) (invoke-restart 'alpha) (add-result 'error-handler-return))) (&warning (lambda (E) (add-result 'warning-handler-begin) (invoke-restart 'beta) (add-result 'warning-handler-return)))) (begin (add-result 'body-begin) (signal C) (add-result 'body-return))) (alpha (lambda () (add-result 'restart-alpha) 1)) (beta (lambda () (add-result 'restart-beta) 2))))) (restarts-outside/handlers-inside (make-error)) ⇒ (1 (body-begin error-handler-begin restart-alpha)) (restarts-outside/handlers-inside (make-warning)) ⇒ (2 (body-begin warning-handler-begin restart-beta)) #| end of body |# ) ;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition, ;;call a handler, invoke a restart. ;; (internal-body (define (restarts-inside/handlers-outside C) (with-result (handler-bind ((&error (lambda (E) (add-result 'error-handler-begin) (invoke-restart 'alpha) (add-result 'error-handler-return))) (&warning (lambda (E) (add-result 'warning-handler-begin) (invoke-restart 'beta) (add-result 'warning-handler-return)))) (restart-case (begin (add-result 'body-begin) (signal C) (add-result 'body-return)) (alpha (lambda () (add-result 'restart-alpha) 1)) (beta (lambda () (add-result 'restart-beta) 2)))))) (restarts-inside/handlers-outside (make-error)) ⇒ (1 (body-begin error-handler-begin restart-alpha)) (restarts-inside/handlers-outside (make-warning)) ⇒ (2 (body-begin warning-handler-begin restart-beta)) #| end of body |# ) ;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition, ;;call a handler, invoke a restart. ;; (internal-body (define (restarts-inside/nested-handlers C) (with-result (handler-bind ((&error (lambda (E) (add-result 'error-handler-begin) (invoke-restart 'alpha) (add-result 'error-handler-return)))) (handler-bind ((&warning (lambda (E) (add-result 'warning-handler-begin) (invoke-restart 'beta) (add-result 'warning-handler-return)))) (restart-case (begin (add-result 'body-begin) (signal C) (add-result 'body-return)) (alpha (lambda () (add-result 'restart-alpha) 1)) (beta (lambda () (add-result 'restart-beta) 2))))))) (restarts-inside/nested-handlers (make-error)) ⇒ (1 (body-begin error-handler-begin restart-alpha)) (restarts-inside/nested-handlers (make-warning)) ⇒ (2 (body-begin warning-handler-begin restart-beta)) #| end of LET |# ) ;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition, ;;call a handler, invoke a restart. ;; (internal-body (define (nested-restarts/handlers-outside C) (with-result (handler-bind ((&error (lambda (E) (add-result 'error-handler) (invoke-restart 'alpha))) (&warning (lambda (E) (add-result 'warning-handler) (cond ((find-restart 'beta) => (lambda (handler) (invoke-restart handler))))))) (restart-case (restart-case (begin (add-result 'body-begin) (signal C) (add-result 'body-return)) (alpha (lambda () (add-result 'restart-alpha) 1))) (beta (lambda () (add-result 'restart-beta) 2)))))) (nested-restarts/handlers-outside (make-error)) ⇒ (1 (body-begin error-handler restart-alpha)) (nested-restarts/handlers-outside (make-warning)) ⇒ (2 (body-begin warning-handler restart-beta)) #| end of body |# ) ;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition, ;;call the first handler, the first handler declines, call ;;the second handler, invoke a restart. ;; (with-result (handler-bind ((&message (lambda (E) (add-result 'outer-message-handler-begin) (invoke-restart 'alpha E) (add-result 'outer-message-handler-return)))) (handler-bind ((&message (lambda (E) (add-result 'inner-message-handler)))) (restart-case (begin (add-result 'body-begin) (signal (make-message-condition "ciao")) (add-result 'body-return)) (alpha (lambda (E) (add-result 'alpha-restart) (condition-message E))))))) ⇒ ("ciao" (body-begin inner-message-handler outer-message-handler-begin alpha-restart))
Next: restarts restart-case, Previous: restarts ignore-errors, Up: restarts [Index]