Subject: Re: distinction?
From: (Rob Warnock)
Date: 9 Dec 2000 14:06:25 GMT
Newsgroups: comp.lang.lisp
Message-ID: <90te91$8r0ao$>
Kent M Pitman  <> wrote:
| Some Scheme implementations offer DYNAMIC-WIND, which is the generalization
| of special variable binding at the data level.  They tend to stop short of
| providing syntax to make it as convenient as CL's specials, but it does 
| offer more power.

Several Scheme implementations also offer "fluid-let", which is much
more convenient to use than dynamic-wind if all you need is just
dynamic binding of variables. Fluid-let interacts correctly with
dynamic-wind (not surprising, since it's usually implemented using it).

MzScheme, in particular, also provides a mechanism called "parameters"
procedures that store some value inside themselves [for example,
"current-output-port"]; and a "parameterize" form, which does a
sort of fluid-let for parameters.

|   (DYNAMIC-WIND winder unwinder body)
| calls winder (a function of no arguments) to set up for the body, then
| calls unwinder (a function again of no arguments) to unset the body.

Actually, following the minutes of the June '92 meeting, R5RS ordered
the arguments slightly differently:

    (dynamic-wind before body after)

| It's allowed to do this as many times as needed, not just at start and
| end of body, and can be used to implement the part of process
| scheduling that unwinds special variable bindings (as well as other
| dynamic bindings custom to the user's applications) on a process switch.

The last time this topic came up, you also implied that dynamic-wind
was useful only for process switching, but it's far more general
than that. It's also useful wherever call/cc is used, e.g., doing
backtracking/nondeterminism, implementing "generators", for implementing
fluid-let, and as the basis of an exception system.

*Unfortunately* for the latter use, two things are missing from
the Scheme spec [though provided in most reasonable implementations]:
(1) There is no guarantee that primitive errors (e.g., divide-by-zero)
will use call/cc to throw the error, thus there's no guarantee that the
"after" thunk of dynamic-winds will be executed on errors; and (2) even
if #1 were fixed, R5RS says "The effect of using a captured continuation
to enter or exit the dynamic extent of a call to before or after is
undefined", which means that strictly speaking you can't use dynamic-wind
to implement "catch" or exception restarts. That is, the following code
isn't guaranteed to work:

	(define (eval-safely expr)
	  (let ((done #f))
	      (lambda (k)
		  (lambda () #f)
		  (lambda () (let ((val (eval expr)))
			       (set! done #t)
		  (lambda () (when (not done) (k 'caught-error))))))))

Fortunately, in most Schemes, it does work:  ;-}

	> (eval-safely '(+ 1 2))
	> (eval-safely '(/ 1 0))
	/: division by zero


Rob Warnock, 31-2-510
Network Engineering
Silicon Graphics, Inc.		Phone: 650-933-1673
1600 Amphitheatre Pkwy.		PP-ASEL-IA
Mountain View, CA  94043