[Haskell-beginners] lazy IO in readFile

Daniel Fischer daniel.is.fischer at web.de
Sat May 8 08:16:27 EDT 2010


On Saturday 08 May 2010 04:47:14, Andrew Sackville-West wrote:
>
> Please ignore, for the moment, whatever *other* problems (idiomatic or
> just idiotic) that may exist above and focus on the IO problem.
>

Sorry, can't entirely. Unless the number of rss items remains low, don't 
use lists, use a Set.

> This code works fine *if* the file "testfile" has in it some subset of
> the testData list. If it has the complete set, it fails with a "resource
> busy" exception.
>
> Okay, I can more or less understand what's going on here. Each letter
> in the testData list gets compared to the contents of the file, but
> because they are *all* found, the readFile call never has to try and
> fail to read the last line of the file. Thus the file handle is kept
> open lazily waiting around not having reached EOF.  Fair enough.
>
> But what is the best solution? One obvious one, and the one I'm using
> now, is to move the appendFile call into a function with guards to
> prevent trying to append an empty list to the end of the file. This
> solves the problem not by forcing the read on EOF, but by not
> bothering to open the file for appending:
>
> writeHistory [] = return ()
> writeHistory ni = appendFile "testfile" . unlines $ ni
>
> And this makes some sense. It's silly to try to write nothing to a
> file.

Yes. In any case,

    unless (null newItems) $ appendFile "testfile" $ unlines newItems

seems cleaner.

>
> But it also rubs me the wrong way. It's not solving the problem
> directly -- closing that file handle. So there's my question, how can
> I close that thing? Is there some way to force it?

For almost all practical purposes, there is (despite the fact that what 
Stephen said is basically right, although a little overstated in my 
opinion).
You have to force the entire file to be read, the standard idiom is using

  x `seq` doSomethingElse

where x is a value that requires the entire file to be read, in your case
x = length currItems is a natural choice.
That way, you effectively have made readFile strict without sacrificing too 
much niceness of the code (withFile and hGetLine mostly are much uglier 
IMO).

It is not entirely failsafe because the file handle needn't be immediately 
closed upon encountering EOF, it can linger until one of the next GCs, but 
if you do something substantial between reading the file and trying to 
reopen it for appending, it is very unlikely that it's not yet closed (not 
impossible, hence almost all and not all).

> Do I need to rework
> the reading to read one line ahead of whatever I'm testing against
> (thereby forcing the read of EOF and closing the file)?
>
> thanks
>
> A



More information about the Beginners mailing list