From: Ng Pheng Siong
Subject: restarting
Date: 
Message-ID: <c3clfd$lh0$1@reader01.singnet.com.sg>
Hi,

I have the following:

(defun x (item)
  (handler-bind ((error #'(lambda (c)
			    (let ((r (find-restart 'duh c)))
			      (if r (invoke-restart r))))))
    (case item
      (1 1)
      (2 "two")
      (otherwise (error "Duh!")))))

(defun dox (list)
  (let ((res nil))
    (dolist (x list)
      (push (restart-case (x x)
	      (duh () (x 1)))
	    res))
    (nreverse res)))

* (dox '(1 2))
(1 "two")
* (dox '(1 2 3))
(1 "two" 1)

Reading the CLHS, I'd imagined that I could write dox naively and
restart-case (or something) its invocation to still get the above
result:

(defun dox2 (list)
  (let ((res nil))
    (dolist (x list)
      (push (x x) res))
    (nreverse res)))

Is it possible to keep dox2 (mostly) as is, and have (dox2 '(1 2 3))
return '(1 "two" 1)? If yes, how?

TIA for any hints. Cheers.


-- 
Ng Pheng Siong <····@netmemetic.com> 

http://firewall.rulemaker.net -+- Firewall Change Management & Version Control
http://sandbox.rulemaker.net/ngps -+- Open Source Python Crypto & SSL

From: Kaz Kylheku
Subject: Re: restarting
Date: 
Message-ID: <cf333042.0403181635.766dcf2b@posting.google.com>
····@netmemetic.com (Ng Pheng Siong) wrote in message news:<············@reader01.singnet.com.sg>...
> Hi,
> 
> I have the following:
> 
> (defun x (item)
>   (handler-bind ((error #'(lambda (c)
> 			    (let ((r (find-restart 'duh c)))
> 			      (if r (invoke-restart r))))))
>     (case item
>       (1 1)
>       (2 "two")
>       (otherwise (error "Duh!")))))

Using an error handler here is kind of pointless, because you are
generating the error close to where you are catching it. In effect,
you can write this function as:

  (defun x (item)
    (case item
      (1 1)
      (2 "two")
      (otherwise (let ((r (find-restart 'duh)))
                   (if r 
                     (invoke-restart r)
                     (error "Duh!"))))))

No error handler necessary, because your logic is ``if the item is not
1 or 2, the invoke the DUH restart if it is visible, or else propagate
an error''.

Error handlers are most advantageous when they are separated from the
place that raises the condition, and from the restarts.
 
> Reading the CLHS, I'd imagined that I could write dox naively and
> restart-case (or something) its invocation to still get the above
> result:
> 
> (defun dox2 (list)
>   (let ((res nil))
>     (dolist (x list)
>       (push (x x) res))
>     (nreverse res)))

There is no way to do this without coding X such that it explicitly
provides some kind of non-local dynamic return point, such as a
restart, CATCH or whatever.

Other than that, you can totally separate out the logic which makes
the decision to jump to that restart point.

Example;

   (defun x (item)
     (catch 'replacement 
       (case item
         (1 1)
         (2 "two")
         (otherwise (error "Help, I need advice with a
replacement!")))))

Okay, so no we need an error handler which traps the error and looks
for advice. That advice is the DUH restart.

    (handler-bind ((error #'(lambda (cond)
                              (let ((r (find-restart 'duh)))
                                (if r
                                  (throw 'replacement 
                                         (invoke-restart r)))))))
      (restart-bind ((duh #'(lambda () 1)))  ;; 1 is the replacement
        (dox2 '(1 2 3))))   ;; call the ``naive'' dox2

    ==> (1 "two" 1)   ;; Hey!
                                    

Note how we separate the restart and handlers from the main logic of
the code. You can set up these handlers far, far away from DOX2. They
can be at the top level somewhere, and the call to DOX2 can be buried
deep within many levels of dynamic nesting. It also doesn't matter
what order they are in; the RESTART-BIND can surround the
HANDLER-BIND.

Note that RESTART-BIND is used not RESTART-CASE. Why? Because
RESTART-BIND does *not* perform the non-local exit before invoking its
handler. A non-local exit would kill your logic here because it would
escape straight out of the call from DOX2. Game over. The RESTART-BIND
construct lets you write restart handlers which can return. And when
that happens, control goes back to the INVOKE-RESTART.  Our restart
lambda returns the value 1 which then pops out of the INVOKE-RESTART
call back in the error handler, and that value is then HROW'n to the
CATCH associated with the REPLACEMENT symbol.
From: Ng Pheng Siong
Subject: Re: restarting
Date: 
Message-ID: <c3df74$c2q$1@mawar.singnet.com.sg>
According to Kaz Kylheku <···@ashi.footprints.net>:
>   (defun x (item)
>     (case item
>       (1 1)
>       (2 "two")
>       (otherwise (let ((r (find-restart 'duh)))
>                    (if r 
>                      (invoke-restart r)
>                      (error "Duh!"))))))
> 
> No error handler necessary, because your logic is ``if the item is not
> 1 or 2, the invoke the DUH restart if it is visible, or else propagate
> an error''.

Yeah, after sleeping on it, I changed X to this too.

> There is no way to do this without coding X such that it explicitly
> provides some kind of non-local dynamic return point, such as a
> restart, CATCH or whatever.
>
> [snip code example and exposition]

Thank you for the explanation.
    
I had also tried CATCH/THROW but got it wrong. Don't remember how.

Thanks again. Cheers.

-- 
Ng Pheng Siong <····@netmemetic.com> 

http://firewall.rulemaker.net -+- Firewall Change Management & Version Control
http://sandbox.rulemaker.net/ngps -+- Open Source Python Crypto & SSL
From: Peter Seibel
Subject: Re: restarting
Date: 
Message-ID: <m365d2vxrs.fsf@javamonkey.com>
····@netmemetic.com (Ng Pheng Siong) writes:

> Hi,
>
> I have the following:
>
> (defun x (item)
>   (handler-bind ((error #'(lambda (c)
> 			    (let ((r (find-restart 'duh c)))
> 			      (if r (invoke-restart r))))))
>     (case item
>       (1 1)
>       (2 "two")
>       (otherwise (error "Duh!")))))
>
> (defun dox (list)
>   (let ((res nil))
>     (dolist (x list)
>       (push (restart-case (x x)
> 	      (duh () (x 1)))
> 	    res))
>     (nreverse res)))
>
> * (dox '(1 2))
> (1 "two")
> * (dox '(1 2 3))
> (1 "two" 1)
>
> Reading the CLHS, I'd imagined that I could write dox naively and
> restart-case (or something) its invocation to still get the above
> result:
>
> (defun dox2 (list)
>   (let ((res nil))
>     (dolist (x list)
>       (push (x x) res))
>     (nreverse res)))
>
> Is it possible to keep dox2 (mostly) as is, and have (dox2 '(1 2 3))
> return '(1 "two" 1)? If yes, how?
>
> TIA for any hints. Cheers.

Well, you're going to have to bind a restart at some point. But you
can indeed leave dox2 as is as long as some code higher up the stack
binds the restart for you. But since you don't want to unwind the
stack you'll need to use RESTART-BIND instead of RESTART-CASE which
means that the handler will then have to transfer control somehow to
"handle" the condition. So, if you leave DOX2 as you have it above and
change X as shown here:

  (defun x (item)
    (handler-bind ((error #'(lambda (c)
                              (let ((r (find-restart 'duh c)))
                                (if r (return-from x (invoke-restart r)))))))
      (case item
        (1 1)
        (2 "two")
        (otherwise (error "Duh!")))))

Then you can use RESTART-BIND anywhere above the call to DOX2 to set
up the appropriate DUH restart. The DUH restart is responsible for
returning a value that will be returned in turn by X:

  (defun foo (args)
    (restart-bind ((duh #'(lambda () (x 1))))
      (dox2 args)))

Or, if you don't need all the flexibility of being able to provide
different restarts, you could just have the handler take care of
computing the replacement result:


  (defun x (item)
    (handler-bind ((error #'(lambda (c) (return-from x (x 1)))))
      (case item
        (1 1)
        (2 "two")
        (otherwise (error "Duh!")))))

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Ng Pheng Siong
Subject: Re: restarting
Date: 
Message-ID: <c3ddlh$c17$1@mawar.singnet.com.sg>
According to Peter Seibel  <·····@javamonkey.com>:
>   (defun x (item)
>     (handler-bind ((error #'(lambda (c)
>                               (let ((r (find-restart 'duh c)))
>                                 (if r (return-from x (invoke-restart r)))))))
>       (case item
>         (1 1)
>         (2 "two")
>         (otherwise (error "Duh!")))))

return-from! Of course! 

> Or, if you don't need all the flexibility of being able to provide
> different restarts, you could just have the handler take care of
> computing the replacement result:

Yes I do. X is used in several ways, DOX being one of them.  X can't
predict how the caller may want to handle DUH. Protocol, as Kent Pitman
likes to say.

Thank you, Peter.


-- 
Ng Pheng Siong <····@netmemetic.com> 

http://firewall.rulemaker.net -+- Firewall Change Management & Version Control
http://sandbox.rulemaker.net/ngps -+- Open Source Python Crypto & SSL