From: Pete Halverson
Subject: Re: Automatically continuing from errors
Date: 
Message-ID: <C39wBw.Ls3@crdnns.crd.ge.com>
In article <············@FRIDGE.AI.CS.YALE.EDU> ·············@cs.yale.edu writes:
>
>I'm having some trouble figuring out the CL condition system.  My
>problem is that I'm using someone else's code which, for some reason
>unknown to me, tries to add bignums using fixnum arithmetic.  I'm
>using Lucid, and the debugger gives me a continuation which will
>return the proper (bignum) result anyway.  What I'd like to do is put
>in a condition handler which will do that for me.  The problem is
>getting control back to the caller.  

The appropriate way to have a "continuation" (more properly called a
"restart", since a continuation is really something different in Lisp)
automatically invoked by a condition handler, as if the user had explicitly
called it from the debugger, is by using INVOKE-RESTART inside a
HANDLER-BIND clause, e.g.

   (defun robust-adder (x y)
     (handler-bind ((simple-error
                     #'(lambda (err)
                         (declare (ignore err))
                         (when (find-restart 'use-bignum)
                           (invoke-restart 'use-bignum)))))
       (fragile-adder x y)))

Note that this depends on the restart having a name and you knowing what
that name is (here, I used USE-BIGNUM as an example).  To find the name of
the restart you want, the easiest way is to run the problematic code until
you drop into the debugger, get the list of all possible restarts using
COMPUTE-RESTARTS, and look for the restart you need using RESTART-NAME:

   > (fragile-adder most-positive-fixnum most-positive-fixnum)
   >>Error: The result 1073741822 is not a fixnum.

   FRAGILE-ADDER:
      Required arg 0 (X): 536870911
      Required arg 1 (Y): 536870911
       0: Return the bignum anyway.
   :A  1: Abort to Lisp Top Level

   -> (mapcar #'restart-name (compute-restarts))
   (ABORT USE-BIGNUM ABORT)

If the restart in question is anonymous (RESTART-NAME returns NIL), things
are a bit uglier.  Instead of using FIND-RESTART, your handler will need to
search the restart list by hand, usually looking inside the restart objects
using system internals for some documentation string or such.

   (defun robust-adder (x y)
     (handler-bind ((simple-error
                     #'(lambda (err)
                         (let ((restart
                                 (find-if
                                    #'(lambda (restart)
                                        <ugly system-dependent predicate
                                        goes here>)
                                    (compute-restarts err))))
                           (when restart
                             (invoke-restart restart))))))
       (fragile-adder x y)))

Hope this is useful.

Pete Halverson                                      INET: ·········@crd.ge.com 
GE Corporate R&D Center                       UUCP: uunet!crd.ge.com!halverson
Schenectady, NY