Subject: Re: Condition/Exception Handling
From: rpw3@rigden.engr.sgi.com (Rob Warnock)
Date: 1996/10/01
Newsgroups: comp.lang.scheme
Message-ID: <52qlm4$i51@tokyo.engr.sgi.com>

Malcolm Chan Chiang Yoeng <malcolm@malcolm.kcbbs.gen.nz> 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 (k)
      (dynamic-wind
	(lambda () (set! done #f))
	(lambda () (...whatever you want protected...) (set! done #t))
	(lambda () (if (not done)
		     (begin
		       ...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:

	http://www.cs.rice.edu/CS/PLT/packages/doc/mzscheme/index.html


-Rob

-----
Rob Warnock, 7U-550		rpw3@sgi.com
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