Malcolm Chan Chiang Yoeng <email@example.com> wrote:
| A program I'm writing needs the ability to handle exceptions that may
| be generated in the course of its execution. Having had some Common
| Lisp experience, I realise that CL can handle this, in the form of
| conditions. What is the Scheme analogue of this? Is it a feature
| that's available on common implementations, say, SCM?
Since exception handling as such is not part of the formal Scheme
standard(s), facilities vary widely among implementations. However,
the infamous "June 92 Meeting" [see the Scheme archives] ratified
(for R5RS, if it ever...) a mechanism that was already implemented
in many Scheme dialects (including SCM and MzScheme) called "dynamic-wind",
which is a lot like CL's "unwind-protect" except that all the args
are thunks (rather than forms), and there is an additional "pre-entry"
case which is needed since the main body might be re-entered using
a captured continuation. The form is:
(dynamic-wind thunk1 thunk2 thunk3)
First "thunk1" is called, then "thunk2" is called, then "thunk3" is called,
and the normal value of the "unwind-protect" is the value of "thunk2".
However, the execution of "thunk2" is protected against non-local exit
*and* re-entry. "Thunk1" is guaranteed to be executed before "thunk2"
is (re)entered, and "thunk3" is guaranteed to be executed before "thunk2"
is (re)exited -- no matter how many times entry/exit occurs. A coding
pattern I've seen used (for an "unwind-protect" sort of behavior) is:
(let ((done #f))
(call/cc ; or call/ce, if you prefer it (and have it)
(lambda () (set! done #f))
(lambda () (...whatever you want protected...) (set! done #t))
(lambda () (if (not done)
...whatever cleanup you need to do...
(k ...whatever you want the fail-value to be...))))))))
[Caveat: For MzScheme (but not SCM), you also need to (set! done #t) in
the "cleanup" before calling the exit continuation, otherwise it loops
forever because "thunk3" gets re-entered *again* on the way out. But
I can't really complain. The June 92 meeting explicitly left unspecified
the semantics of invoking a continuation while in "thunk3". (*sigh*)]
I used patterns similar to the above when writing a shell-style Scheme
REPL [TBA "soon"] that is portable between SCM & MzScheme (at least).
Routines named "eval-safely/apply-safely/read-safely" let me (re)capture
control in the event of user syntactic or semantic errors.
If you're looking for something with more "built-in stuff" than just
dynamic-wind, MzScheme *also* has a complete-separate and particularly
fine-grained exception-handling mechanism, which the author says is the
one "proposed by Friedman, Haynes, and Dybvig". Click on "Exceptions" in:
Rob Warnock, 7U-550 firstname.lastname@example.org
Silicon Graphics, Inc. http://reality.sgi.com/rpw3/
2011 N. Shoreline Blvd. Phone: 415-933-1673 FAX: 415-933-0979
Mountain View, CA 94043 PP-ASEL-IA