[Haskell-cafe] IO and lazyness.

Claus Reinke claus.reinke at talk21.com
Tue Mar 6 17:18:19 EST 2007

> Also, following Jeremy's advice, I replaced the last line of rechf2
> with   return $! rech r $ lines f       and indeed it works.
> I don't understand why it doesn't without the !
> The documentation for hGetContents says the items are read on demand.
> the function rech needs the strings so they should be read on demand.
> This confuses me :(

that kind of issue comes up frequently, so here is my go at a description. if you 
find this helpful, it would be nice if you could put up your questions and answers 
on the wiki; if you don't find it helpful, or if the wiki already explains the issues, 
please ignore the following.

[I've hereby set up an implicit source of input, which you can read at your own
 convenience, as far as you need:-]

hGetContents sets up an implicit computation that will read input on demand for 
its output. you're not supposed to do anything else with either the input or the 
computation, other than consuming its output, until the demand for the output has 
been satisfied completely (and hence the input has been read as far as needed).

openFile/<readsomething>/hClose give you explicit control over the sequence 
of file operations. explicit control means you're responsible for organizing things.

either style of i/o works on its own, but don't try to mix them, certainly not on
the same file/handle.

concretely, you're explicitly requesting the file handle to be closed, after the
implicit computation has been set up, but *before* any of its results have been
demanded. that cuts off the input source for the implicit computation. so when
later parts of the program demand its output, there is nothing left to be delivered.

[rechf only returns an access point to the results of the implicit computation]

your options: 

- move the explicit hClose backwards, until you're sure that you've all the 
    output you want, and hence are done with the input (sometimes tricky)

- avoid the explict hClose entirely, use only implicit i/o on that file (okay if 
    you don't need many handles)

- move the demand for the output of the implicit computation forward, to
    ensure that its input will be consumed *before* the explicit hClose cuts
    it off (involves seq or $! and some forced traversal of the complete 
    output, eg, via length)

- avoid the implicit hGetContents entirely, use only explicit i/o on that file
    (sometimes necessary, but usually more complicated)


[i've hereby explicitly closed the source of input, suggesting there is 
 nothing more to come]

ps. there should be library functions for getContentsNow/readFileNow,
    giving the convenience of implicit i/o without the advantages and pitfalls
    of lazy i/o.as long as there aren't, you might find it both instructive and
    helpful in practice to define them yourself?

[but then i've added more input here, after the closing; will it be read
 implicitly, or ignored explicitly?-]

More information about the Haskell-Cafe mailing list