IO monad and lazy evaluation
Glynn Clements
glynn.clements@virgin.net
Thu, 22 May 2003 20:11:02 +0100
Graham Klyne wrote:
> Thanks for your comments. (I had overlooked "readFile", which certainly
> looks safer.
It isn't:
readFile :: FilePath -> IO String
readFile name = openFile name ReadMode >>= hGetContents
> The broader debate I was trying to evoke was: how, as a programmer using a
> combination of monads and non-strict functions, can I be confident that
> there aren't hidden interactions waiting to bite?
The problem isn't monads, or lazy functions, or even the interactions
between them. The problem is specifically lazy I/O, which is basically
a fudge which usually works in simple cases.
The "normal" (i.e. strict) I/O functions are perfectly safe.
> Using the hOpen ... hClose vs readFile case as an example, is the
> difficulty here to do with the interleaving of multiple statements that
> modify some state with non-strict functions that return results based on
> some particular instance of that state? Is this really a fundamental mismatch?
The problems arise from the use of unsafeInterleaveIO (with which
hGetContents is implemented), which essentially allows I/O operations
to "escape" from the IO monad. The net result is that the actual I/O
operations (for which ordering matters) occur as a side-effect of
evaluating pure expressions.
The simple solution is not to use unsafeInterleaveIO, either directly
or via hGetContents, getContents, readFile or interact.
--
Glynn Clements <glynn.clements@virgin.net>