Hi, I've prepared a start of a prototype restart library based on Taylor Campbell's proposal [1] which is itself based on the exception handling system of Common Lisp and MIT Scheme.
A trivial example to show the functionality is the following definition of a toy replacement for '/' where the 'error:divide-by-zero' is a custom condition making use of restarts: (define (/:fbe num . dens) (if (any zero? dens) (apply error:divide-by-zero '/:fbe (cons num dens)) (apply / num dens))) Now when you divide by zero you end up in the debugger where you have a new meta command called 'restart' which allows you to list the available restarts and to call one: scheme@(guile-user)> (1+ (/:fbe 1 0)) <unnamed port>:51:4: In procedure #<procedure 3158700 at <current input>:51:0 ()>: <unnamed port>:51:4: ERROR: R6RS exception: 1. &restartable: (#<r6rs:record:<resterter>> #<r6rs:record:<resterter>> #<r6rs:record:<resterter>>) 2. ÷-by-zero 3. &message: "Division by zero." 4. &who: /:fbe 5. &irritants: (1 0) Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. scheme@(guile-user) [1]> ,restart The following restarts are available: 1: (use-value) Specify a value to use instead of (/:fbe 1 0). 2: (abort) Abort computation. 3: (greatest-fixnum) Use greatest-fixnum instead of (/:fbe 1 0). scheme@(guile-user) [1]> ,restart 1 Enter a value: 100 $2 = 101 scheme@(guile-user)> Of course you can also use the restarts programmatically: (define (1+reciprocal-of value) (1+ (/:fbe 1 value))) (with-exception-handler (lambda (c) (if (divide-by-zero? c) (use-value 20 c))) (lambda () (1+reciprocal-of 0))) => 21 The reason for writing to this list is that, to be useful, restarts should be included at a fairly low level. This means that they would be best included in the native Guile exception handling system. This would allow amazing things like extensions of the Scheme interpreter as exemplified by the MIT Scheme Scmutils library [2] where you can, e.g., apply a vector of functions to a symbol ('up' denotes contravariant vectors and are just Scheme vectors): ((up sin cos) 't) #| (up (sin t) (cos t)) |# Without restarts in Guile I need to use (the custom, generic combinators based) 'apply' explicitly. Even then, nested applications do not work. scheme@(guile-user)> (apply (up sin cos) '(t)) $3 = (up (sin t) (cos t)) scheme@(guile-user}#)> ((up sin cos) 't) ERROR: In procedure #(#<procedure 16fd090 at scmutils/kernel/ghelper.scm:78:9 (arg)> #<procedure 16fd000 at scmutils/kernel/ghelper.scm:78:9 (arg)>): ERROR: Wrong type to apply: #(#<procedure 16fd090 at scmutils/kernel/ghelper.scm:78:9 (arg)> #<procedure 16fd000 at scmutils/kernel/ghelper.scm:78:9 (arg)>) Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. scheme@(guile-user) [1]> So the questions are: * Would such functionality be welcome? * What would this imply in practical terms? I've barely started looking into Guile source and don't yet understand what is implemented in C and what in Scheme. It would be of great help if someone could give an overview explanation of the current exception handling design. Thanks, Federico [1] mumble.net/~campbell/proposals/restart.scm [2] http://groups.csail.mit.edu/mac/users/gjs/6946/linux-install.htm
restart.tar.gz
Description: GNU Zip compressed data