[Haskell-beginners] Moment of enlightenment for lazy evaluation

Tom Tobin korpios at korpios.com
Sat Feb 20 12:00:21 EST 2010


Instead of a question, I thought I'd share a moment of lazy-evaluation
enlightenment I had last night.

I have some code that recursively descends a directory, gets the SHA1
hashes for all the files, and builds a map of which file paths share
the same SHA1 hash.  The code that actually generates the hash looked
like this:

sha1file :: FilePath -> IO String
sha1file fn = do
  bs <- expandPath fn >>= BSL.readFile
  return $ PureSHA.showDigest $ PureSHA.sha1 bs

Everything worked fine on paths without many files in them, but choked
on paths with many files:

"Exception: getCurrentDirectory: resource exhausted (Too many open files)"

This was driving me crazy; ByteString.Lazy.readFile is supposed to
close the file once it's done.  I kept going over my code, wondering
what was at fault, until it finally clicked: *the hashes weren't being
generated until I actually tried to view them*, and thus all the files
were being held open until that point!  I made a single change to my
"sha1file" function:

sha1file :: FilePath -> IO String
sha1file fn = do
  bs <- expandPath fn >>= BSL.readFile
  return $ PureSHA.showDigest $! PureSHA.sha1 bs

(the "$!") ... and everything worked perfectly.  The code now finished
processing each file before opening the next one, and I was happy.
:-)


More information about the Beginners mailing list