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>