1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
S9fES (catch procedure^1) ==> object
(catch-tag? object) ==> boolean
(throw catch-tag object) ==> undefined
CATCH packages the current escape continuation into a "catch tag"
and passes it to PROCEDURE^1, which must be a procedure of one
argument. The procedure will then evaluate and return a result,
which will be returned by CATCH -- unless the procedure applies
THROW to the catch tag passed to it.
When PROCEDURE^1 applies THROW to the catch tag generated by CATCH,
then evaluation of the procedure will be aborted immediately and
control will be passed back to CATCH. The result of CATCH will in
this case be the second argument (OBJECT) of the corresponding THROW.
The CATCH-TAG? predicate tests the given OBJECT for being a catch
tag and returns #T only if this is the case.
A catch tag that escapes the dynamic extent of CATCH is no longer
valid and throwing it will cause an undefined result. That is,
CATCH only captures its escape continuation, so catch tags can
only be used to escape the dynamic extent of CATCH, but not to
reenter it.
In S9fES, the catch/throw mechanism is a much more lightweight
alternative to full continuations (which it also provides). CATCH
and THROW are typically used to implement non-local exits (see the
examples below).
In portable R4RS Scheme, drop-in replacements for CATCH and THROW
can be defined like this:
(define catch call-with-current-continuation)
(define (throw tag expr) (tag expr))
Examples:
(cons 'foo (catch
(lambda (ct)
(cons 'baz (throw ct 'bar))))) ==> (foo . bar)
(define (list-length a)
(catch
(lambda (improper)
(let loop ((a a))
(cond ((null? a) 0)
((pair? a) (+ 1 (loop (cdr a))))
(else (throw improper #f)))))))
(list-length '(1 2 3)) ==> 3
(list-length '(1 2 . 3)) ==> #f
|