lazily handling exceptions in lazy sources (Re: [Haskell-cafe] Re:
oleg at pobox.com
oleg at pobox.com
Thu Mar 15 04:02:31 EDT 2007
> the usual caveats about unsafePerformIO apply, so perhaps you wouldn't want
> to use this in a database library..
Indeed. This is quite problematic, from the practical point of view of
making resources difficult to control (cf. another thread of file
handle leakage), to the theoretical point that side effects and lazy
evaluation strategy is a bad mix, severely limiting the equational
theory and making the code hard to reason about. I do care about all
of these issues; otherwise I would have programmed in C.
That reminds of Simon Peyton-Jones POPL2003 presentation, the
retrospective on Haskell. He said that the fact that lazy evaluation
and side effects are poor match has kept the designers from adding all
kinds of problematic hacks to the language. The laziness has kept
Haskell pure -- until the monad (notation) has come along and showed
how to do side-effects in the principled way. If keeping the purity
and keeping unsolved problems open until a principled solution comes
along have worked so well in the past, why to change now?
As to the original question
>> 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)
a better (albeit still quite unsatisfactory) answer might be to change the
interface of getContents so it would take the handler as an argument:
newGetContents :: (Exception -> IO String) -> IO String
The old getContents is equivalent to "newGetContents (const (return ))".
If the handler needs to notify the rest of the program of an error, it
may save the information from the exception in a IORef defined in
outer scopes. If this looks like the inversion of control, that's
because it is...
Often the problem can be solved via a left-fold enumerator, like the
one in Takusen. In the context of reading file, such an enumerator is
One of the examples in that article was specifically reading only a
few characters from a file. With enumerator, we guarantee that file
handles do not leak, that files are closed at the precise and
predictable moments, and we never read the whole file in memory unless
the programmer specifically wishes to.
More information about the Haskell-Cafe