
Simon Marlow wrote:
Simon Marlow:
[Lazy I/O] is nice, but it introduces too many problems. What happens to any I/O errors encountered by the lazy I/O? They have to be discarded, which means you can't effectively use lazy I/O for robust applications anyway.
Surely they are thrown as exceptions which can then be manipulated in pure code using
mapExceptions :: (Exception -> Exception) -> (a -> a)
and caught in the IO monad using catch?
No, the report clearly states that they are discarded.
Could you please point out where? I couldn't find it with a quick look.
Section 11.2.1 in the Library Report, last paragraph.
We could perhaps have our own versions of the lazy I/O operations which throw exceptions, but this in itself is problematic because these kind of exceptions would be asynchronous in nature. If lazy I/O is allowed to raise exceptions, then we have a situation where evaluating anything can raise an I/O exception. In theory this shouldn't be a problem - we all ought to be writing asynchronous-excpetion-safe code anyway to protect against StackOverflow, but an I/O exception is often one that you want to handle gracefully and recover from. I feel distinctly uncomfortable about I/O exceptions being thrown by pure code, and even more uncomfortable about asynchronous I/O exceptions.
Is even the following example from the library report (section 11.8.2) problematic?
import System import Char( toUpper )
main = do [f1,f2] <- getArgs s <- readFile f1 writeFile f2 (map toUpper s)
It depends what you want to happen in the event of a I/O error in the file being read. If you want to reliably clean up, say remove f2 and emit a helpful message, then as Haskell 98 stands you can't do it. If we were to make the lazy I/O raise an exception in the event of an error, then you can do the cleanup, but you have to know which computations can force the lazy I/O and wrap appropriate exception handlers around them. Knowing which computations can force the I/O is problematic. There *is* a reasonable semantics for readFile: read the whole file immediately. You don't have to generate the Haskell String eagerly, just read the whole file into a cache and report any I/O errors. This doesn't work too well for large files, or for using readFile/getContents to write stream processors though. Cheers, Simon