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>