
On Fri, Mar 15, 2013 at 5:52 AM, Jacek Dudek
(1) What is the proper way to reason about lazy IO?
Lazy IO is pull-driven. The stuff that comes out of a lazy read needs to be /pulled/ by some weight to be actually read. The function putStrLn exerts weight, as you've discovered. So does writeFile. What's weightless is a pure function "lifted" (by liftM aka fmap) into IO.
(2) Is there some action less arbitrary that what I cooked up in the second version that explicitly instructs to release a file or some other resource?
Explicitly managing resources means going the whole nine yards of imperative programming. Which means reading and writing in program-specified chunks, opening and closing file handles, dealing with IO errors, etc. If this sounds a lot like manual memory management, that's because it is. So the dream is: is there an analogue of GC doing for IO what GC now does for RAM? Lazy I/O can be thought of as an hors d'oeuvre of that dream. Some have complained about a queasy feeling in the stomach afterward. Some of the strongest detractors of lazy I/O have proposed iteratees as a more realistic substitute. Just a few hours ago, Dan Doel wrote an email [1] to the haskell-cafe list explaining how some problems of Lazy I/O can be resolved by even more laziness, not less. I read his email as keeping the dream alive. (Others may differ.) GC gives the illusion of infinite RAM. What would the illusion of infinite IO be like? So to recap: if you run into issues with Lazy I/O, the fixes include: * Replace lazy with strict I/O. Make sure you have enough RAM, especially if you still use String, as opposed to ByteString. * Use strict I/O but leave off readFile. Chunk explicitly. Code imperatively. * Use iteratees * Use unsafeInterleaveIO. Watch the envelope bend. [1] http://www.haskell.org/pipermail/haskell-cafe/2013-March/107027.html -- Kim-Ee