Is this really a solution? Currently, getContents reports no errors
but does perfect error recovery: the result of the computation prior to
the error is preserved and reported to the caller. Imprecise
exceptions give us error reporting -- but no error recovery. All
previously computed results are lost. Here's a typical scenario:
do l <- getContents
return (map process l)
If an error occurs reading lazy input, we'd like to log the error and
assume the input is terminated with EOF.
i was wondering: could you perhaps use the old Hood Observe trick
to help you out? Hood wraps lazy sources in unsafePerformIO handlers
that log things as they are demanded, then passes them on. you might be
able to use the same to pass things on as they are demanded, while logging
exceptions and replacing exceptional with repaired or default values?
What we'd like are _resumable_ exceptions. The exception handler
receives not only the exception indicator but also the continuation
where the exception has occurred. Invoking this continuation means
error recovery. Resumable exceptions are used extensively in CL; they
are also available in OCaml. So, hypothetically we could write
do l <- getContents
resume_catch (return (map process l))
(\e k -> syslog e >> k )
Besides the obvious typing problem, this won't work for the reason
that exceptions raised in the pure code are _imprecise_ -- that is, no
precise continuation is available, even in principle.
yes, i've often wondered why exceptions are not optionally resumable,
with a handler that may decide to return or abort, depending on how
seriously the protected code is likely to be affected by the exception
in hand. that way, exception handling and normal processing would be
better separated, and simple fault tolerance easier to achieve, whereas
now the exception handler would have to know how to restart the
interrupted computation from scratch.
in terms of imprecise semantics, that might not be a problem, either:
yes, you can't guarantee that the same exception will be raised if you
repeat the experiment, but that is why the handler is in IO already.
no matter what exception and continuation it receives, if the exception
is non-fatal, it can log the problem and return, with a repaired value,
to the pure code that raised the exception.
in terms of stack-based implementation, it might be the simple difference
of clearing the stack in the handler, rather than in the raiser, giving the
handler the option to resume or abort the raiser. or is that too naive?-)
Haskell-Cafe mailing list