Re: new to the condition system



Q wrote:
So, there's no simple way, if a function errors, to just unwind
everything and call the function again?

Sure, there's a few. You just can't recurse indefinitely. Here's a
simple example (assuming you just want to log the error and move on) :

(defun retry (thunk)
(loop
(handler-case
(return-from retry (funcall thunk))
(error (e)
(typecase e
(simple-condition
(apply 'warn
(simple-condition-format-control e)
(simple-condition-format-arguments e)))
(t (warn "Got an error : ~A" e)))))))

CL-USER> (retry 'random-fn)
no problem with me 3
no problem with me 4
no problem with me 0
no problem with me 2
WARNING: im too big 9

no problem with me 1
; Evaluation aborted

hth,

drewc



On Apr 30, 4:09 pm, Kent M Pitman <pit...@xxxxxxxxxxx> wrote:
Q <qal...@xxxxxxxxx> writes:
I'm trying to solve something akin to the following problem:
(defun test-fn ()
(handler-case
(random-fn)
(error (e)
(handler-fn))))
(defun random-fn ()
(loop as rand = (random 10)
do
(if (> rand 8)
(error "im too big ~d~%" rand)
(format t "no problem with me ~d~%" rand))))
(defun handler-fn ()
(format t "WHOOPS, found an error~%")
(test-fn))
Basically, I'd like to run test-fn, and every time random-fn returns
an error, I'd like to report the error and just restart from scratch
with test-fn. As written, these 3 functions very quickly return a
stack overflow, because we're just getting deeper and deeper into new
instances of test-fn. I'm obviously misusing the lisp conditional
system, but I'm a bit confused as to how to use it correctly. Any
help?
To a close approximation, stack is increased by calling functions and
decreased by returning from functions. When you call test-fn, it
sometimes calls handler-fn, increasing stack depth. But handler-fn
doesn't return. It calls test-fn, which you might think is a tail
call, but it's not. So you increase stack depth. test-fn doesn't
return. It calls random-fn, which either loops happily, or eventually
catches an error, in which case test-fn doesn't return, it calls
handler-fn. And the whole mess goes around and around.

This problem would happen with mutual recursion as well. Your problem
is not condition handling. It's tail calls. Nothing in CL encourages
you to assume recursion, even tail recursion, can be done without
increasing stack depth.

One reason for this, so you don't think it's an utter bug, is that
many errors are mysterious to debug if you don't have the ability to
look up the stack and see who called you. Languages that eliminate
tail calls do so as a conscious choice, opting to make some amount of
debugging harder. Also, it's complicated (not impossible, just
subtle) to spec exactly what constitutes a tail call--there are some
odd cases. Historically, it was not something Lisp had traditionally
done, so when we standardized Lisp, we didn't make all existing
implementation strategies illegal by standardizing on it.

While I am quite comfortable working in a language that hasn't got
this required, I'm sympathetic to the desire of implementations to
play with this. There are a number of ways in which we differ from
Scheme and other languages for "good principled reason" but this
particular one is somewhat more arbitrary and obviously in some cases
constraining to people.

There are many days on which I suspect we should have gone to more
trouble to allow declarational ways for users to say they wanted this.
The complexity of that was that it would have meant that such programs
would have not run in implementations that didn't support such
declarations. If memory serves (someone will undoubtedly correct me
if I'm wrong on this, but I haven't looked at the spec on this in
qutie some time), we already have that situation with SAFETY... we
allow implementations to not implement high SAFETY, and we allow
programs to request it, forcing some conforming programs to not be
accepted by some conforming implementations. That sort of compromise
would likely have worked with tail calls.

(I also don't know that much of anyone would object to an
implementation describing itself as being "mostly like CL but with
good support for tail calls" if someone wanted to try implementing it.
See another post I wrote in the last day or so about good labeling
being the most important thing. Conformance criteria are not about
keeping people from experimenting, they are just about how to properly
name the things you experiment with. People should know they are
playing with something that is not conforming, but that's not the same
as saying people should feel horrible guilt for straying.)



--
Posted via a free Usenet account from http://www.teranews.com

.



Relevant Pages

  • Re: Python and Scheme
    ... is that tail recursion make debugging more difficult and that rules ... and the recursive calls happen to be tail recursive. ... Implementations of Scheme are required to be properly tail-recursive. ... This means that an implementations can be both debug friendly and compliant at the same time by keeping a record of the last, say, 20 active tail calls. ...
    (comp.lang.scheme)
  • Re: new to the condition system
    ... (defun random-fn () ... Basically, I'd like to run test-fn, and every time random-fn returns ... sometimes calls handler-fn, increasing stack depth. ... It's tail calls. ...
    (comp.lang.lisp)