On 10/9/10 5:49 PM, Joey Hess wrote:
The function below always returns "", rather than the file's contents.
_Real World Haskell_ touches on how laziness can make this problimatic,
without really giving a solution, other than throwing in a putStr to
force evaluation, which can't be done here. How can I make  hGetContents
strict, to ensure the file contents are really read before it gets closed?

readFile' file = do
        f <- openFile file ReadMode
	-- locking will go here
        s <- hGetContents f
        hClose f
        return s

Haskell won't actually read the file unless you need the contents of the file.  In order to ensure that the file contents are read before it gets close, you need to actually perform an operation that will force evaluation of the file. Haskell will read the file then to perform whatever operation you specify.
    for example
         sendFile file = do
              f<- openFile file ReadMode
              s <- hGetContents f
              sendToNetwork s --made up function
              hClose f

In your example, you're getting "" because the handle is closed, so Haskell doesn't have anything to read.
You say you can't use putStr in this scenario, but if you're reading the file you must be doing something with the contents. Wait to close the handle until after that operation takes place.

Also, I noticed that opening a file and locking it involves a
very verbose seeming dance. (It's 2 lines of code in most other languages.)
Does this indicate that few people bother with file locking in Haskell
and so it still has these rough edges, or that there's a better way to do
it that I have not found yet?

openLocked file = do
        handle <- openFile file ReadMode
        lockfd <- handleToFd handle -- closes handle
        waitToSetLock lockfd (ReadLock, AbsoluteSeek, 0, 0)
        handle' <- fdToHandle lockfd
        return handle'

You should go to haskell.org/hoogle, and search openFile, or check out the Haskell98 report, but I'm under the impression that ghc locks the file for you when you open the file.:
From haskell98 report:

21.2.3  File locking

Implementations should enforce as far as possible, at least locally to the Haskell process, multiple-reader single-writer locking on files. That is, there may either be many handles on the same file which manage input, or just one handle on the file which manages output. If any open or semi-closed handle is managing a file for output, no new handle can be allocated for that file. If any open or semi-closed handle is managing a file for input, new handles can only be allocated if they do not manage output. Whether two files are the same is implementation-dependent, but they should normally be the same if they have the same absolute path name and neither has been renamed, for example.

21.3.1  Opening Files

...

Error reporting: the openFile computation may fail with isAlreadyInUseError if the file is already open and cannot be reopened; isDoesNotExistError if the file does not exist; orisPermissionError if the user does not have permission to open the file



Hope this helps,
Jimmy Wylie