Hello,
The following code seems to show, that the
test-function of restart-case is called with NIL as its argument:
(handler-bind ((error #'(lambda (x) (invoke-restart 'MY-RESTART))))
(restart-case (error "DUMMY ERROR")
(MY-RESTART () :test (lambda (c) (if c
t
(progn
(format t "Test Function was called with NIL")
NIL))) t)))
However the relevant Hyperspec Section implies that it should be called
with the condition:
<quote>
The value supplied by :test value must be a suitable argument to
function. (function value) is evaluated in the current lexical
environment. It should return a function of one argument, the
condition, that returns true if the restart is to be considered
visible.
</quote>
Can anyone explain this to me? Am I misinterpreting the standard or
is it an implementation problem (i am using sbcl here)
Thanks in advance
Norman Werner
PS:
I am aware of this 2005-thread:
http://coding.derkeiler.com/Archive/Lisp/comp.lang.lisp/2005-04/msg01437.html
as well as
http://www.lispworks.com/documentation/HyperSpec/Issues/iss075_w.htm
However they don't seem to answer my question.
Norman Werner wrote:
> Hello,
>
> The following code seems to show, that the
> test-function of restart-case is called with NIL as its argument:
>
> (handler-bind ((error #'(lambda (x) (invoke-restart 'MY-RESTART))))
> (restart-case (error "DUMMY ERROR")
> (MY-RESTART () :test (lambda (c) (if c
> t
> (progn
> (format t "Test Function was called with NIL")
> NIL))) t)))
>
>
> However the relevant Hyperspec Section implies that it should be called
>
> with the condition:
>
> <quote>
> The value supplied by :test value must be a suitable argument to
> function. (function value) is evaluated in the current lexical
> environment. It should return a function of one argument, the
> condition, that returns true if the restart is to be considered
> visible.
> </quote>
hey Norman,
I'm not on a computer with lisp installed, but did you try supplying a
parameter at XX in (MY-RESTART (XX) ...
if I remember correctly (my-restart () ... is equivalent to (my restart
(#1=#:xx) (declare (ignore #1#) ... this could be the problem...
hth
Nick
········@gmail.com schrieb:
> > > (handler-bind ((error #'(lambda (x) (invoke-restart 'MY-RESTART))))
> > > (restart-case (error "DUMMY ERROR")
> > > (MY-RESTART () :test (lambda (c) (if c
> > > t
> > > (progn
> > > (format t "Test Function was called with NIL")
> > > NIL))) t)))
>
> also (handler-bind ((error #'(lambda (x) (invoke-restart 'MY-RESTART
> x)...
>
> hth
>
> Nick
Thanks for the answer -
I tried it - but it did not help.
AFAIK the argument to the restart is independent
to the test - whether the restart is visible.
Norman
Norman Werner wrote:
> ········@gmail.com schrieb:
>
> > > > (handler-bind ((error #'(lambda (x) (invoke-restart 'MY-RESTART))))
> > > > (restart-case (error "DUMMY ERROR")
> > > > (MY-RESTART () :test (lambda (c) (if c
> > > > t
> > > > (progn
> > > > (format t "Test Function was called with NIL")
> > > > NIL))) t)))
> >
> > also (handler-bind ((error #'(lambda (x) (invoke-restart 'MY-RESTART
> > x)...
> >
> > hth
> >
> > Nick
>
> Thanks for the answer -
> I tried it - but it did not help.
>
> AFAIK the argument to the restart is independent
> to the test - whether the restart is visible.
To be honest, I don't see why the test is even being called. The error
is going to the bound
handler which is invoking the restart, it won't be visible anyway, why
call the test function?
AFAICT, getting a NIL indicates the restart was invoked rather than
handled interactively.
CL-USER 1 > (restart-case
(error "foo")
(test ()
:test (lambda (c) (format t "~&got:~A~%" c) t)))
got:foo
Error: foo
1 (continue) TEST
2 (abort) Return to level 0.
3 Return to top loop level 0.
Type :b for backtrace, :c <option number> to proceed, or :? for other
options
CL-USER 2 : 1 > :c 1
NIL
CL-USER 3 > (restart-case
(invoke-restart 'test 7)
(test (x)
:test (lambda (c) (format t "~&got:~A~%" c) t)
x))
got:NIL
7
---
Geoff
Norman Werner wrote:
> ········@gmail.com schrieb:
>
> > > > (handler-bind ((error #'(lambda (x) (invoke-restart 'MY-RESTART))))
> > > > (restart-case (error "DUMMY ERROR")
> > > > (MY-RESTART () :test (lambda (c) (if c
> > > > t
> > > > (progn
> > > > (format t "Test Function was called with NIL")
> > > > NIL))) t)))
> >
> > also (handler-bind ((error #'(lambda (x) (invoke-restart 'MY-RESTART
> > x)...
> >
> > hth
> >
> > Nick
>
> Thanks for the answer -
> I tried it - but it did not help.
>
> AFAIK the argument to the restart is independent
> to the test - whether the restart is visible.
The HyperSpec says of the :test value given to
HANDLER-CASE/HANDLER-BIND:
"The value supplied by :test value must be a suitable argument to
function. (function value) is evaluated in the current lexical
environment. It should return a function of one argument, the
condition, that returns true if the restart is to be considered
visible."
the noteworthy part of that being that the argument to this is a
_condition_.
my guess is that the behavior of this function is more specifically
defined as taking an argument that may be (a) a condition or (b) NIL if
none is supplied
thus it would be relevent in this instance since INVOKE-RESTART
doesn't take an optional condition argument (like FIND-RESTART), so
(handler-bind ((error #'(lambda (x) (invoke-restart 'MY-RESTART))))
...
is finding the appropriate restart like
...#'(lambda (x) (invoke-restart (find-restart 'MY-RESTART)))
intead of
...#'(lambda (x) (invoke-restart (find-restart 'MY-RESTART x)))
thus it makes sense given this supposition that the "condition"
argument in this case could be NIL
it's obvious though that if this is indeed the case this passage should
have been worded differently and this behavious explicitly pointed
out... (though when you think about it, it is an example of the
expressiveness of Lisp: it allows you to have a hand in specifying what
restart you want to be visible even when there is no condition
involded!)
that being said I think there is still something skrewey going on with
your example... (I'm using ACL 8.0 not SBCL)
(handler-bind ((error #'(lambda (x)
(invoke-restart 'my-restart))))
(restart-case (error "dummy error")
(my-restart () :test (lambda (c)
(print c)
nil
'restart-2)
(my-restart () :test (lambda (c)
(print c)
t
'restart-2)))
gets me
NIL
NIL
=> 'RESTART-2
showing that both test functions were called with NIL and that the
second version of my-restart was chosen based on the return value of
the :test functions...
but if I explicitly call FIND-RESTART supplying the optional condition
arg
(handler-bind ((error #'(lambda (x)
(invoke-restart (prog1
(find-restart
'my-restart x)
(print "found restart"))
(restart-case (error "dummy error")
(my-restart () :test (lambda (c)
(print c)
nil
'restart-2)
(my-restart () :test (lambda (c)
(print c)
t
'restart-2)))
I get
#<SIMPLE-ERROR @ #xdc282>
#<SIMPLE-ERROR @ #xdc282>
"found restart"
NIL
NIL
=> RESTART-2
suggesting test is being called by both FIND-RESTART and
INVOKE-RESTART, and indeed
(handler-bind ((error #'(lambda (x)
(invoke-restart 'my-restart))))
(restart-case (error "dummy error")
(my-restart () :test (lambda (c)
c)
'restart-2)
(my-restart () :test (lambda (c)
(not c))
'restart-2)))
throws an error
Nick
Thanks for youre reply which helped a lot.
Just to make sure - I understood everything correctly
(and to help future users with the same problem)
let me formulate this working hypothesis:
1) the usable restarts have to be determined at runtime
by the function FIND-RESTART.
2) This function takes a condition as optional argument
which serves as input to the :test function
3) when invoke-restart is called with a restart-designator
(eg. a symbol) instead of a restart it calls find-restart
- BUT WITHOUT THE OPTIONAL ARGUMENT.
Or by Example:
GOOD:
(handler-bind
((error #'(lambda (x) (invoke-restart (find-restart 'my-restart x)))))
(restart-case (error "DUMMY ERROR")
(MY-RESTART () :test (lambda (c) c) 'OK)))
BAD:
(handler-bind
((error #'(lambda (x) (invoke-restart 'my-restart))))
(restart-case (error "DUMMY ERROR")
(MY-RESTART () :test (lambda (c) c) 'OK)))
Norman
Norman Werner wrote:
> Thanks for youre reply which helped a lot.
> Just to make sure - I understood everything correctly
> (and to help future users with the same problem)
> let me formulate this working hypothesis:
>
> 1) the usable restarts have to be determined at runtime
> by the function FIND-RESTART.
> 2) This function takes a condition as optional argument
> which serves as input to the :test function
> 3) when invoke-restart is called with a restart-designator
> (eg. a symbol) instead of a restart it calls find-restart
> - BUT WITHOUT THE OPTIONAL ARGUMENT.
>
> Or by Example:
>
> GOOD:
> (handler-bind
> ((error #'(lambda (x) (invoke-restart (find-restart 'my-restart x)))))
> (restart-case (error "DUMMY ERROR")
> (MY-RESTART () :test (lambda (c) c) 'OK)))
>
> BAD:
> (handler-bind
> ((error #'(lambda (x) (invoke-restart 'my-restart))))
> (restart-case (error "DUMMY ERROR")
> (MY-RESTART () :test (lambda (c) c) 'OK)))
Since you're writing a test function, how about:
(handler-bind
((error (lambda (error)
(let ((restart (find-restart 'my-restart error)))
(if restart
(invoke-restart restart)
(continue error))))))
...)
---
Geoff