[Haskell-cafe] comprehension generators from IO [a]'s ?

Steve Harris steveofar at gmail.com
Mon Dec 19 14:42:19 EST 2005

[reposted from haskell mailing list where I got no bites :) ]

Folks,
I'm new to using monads, and I'd like some help improving a function
definition that I wrote and which works, but for which I think there
should be a clearer way to write it.

What I'm after is something like:
-- (psuedo-code)
[(b,c,d) |
b <- getDirectoryContents a_dir,
c <- getDirectoryContents (a_dir ++ "/" ++ b),
d <- getDirectoryContents (a_dir ++ "/" ++ b ++ "/" ++ c) ],

ie. where the generators feed from IO actions instead of lists,  but I
gather this comprehension style isn't supported, which is too bad
because it's really easy to read.  (Is this what was meant by "monad
comprehensions" that I've heard reference to?)

Here's how I actually wrote it, using nested folds:

import System.IO

-- Load directory entries 3 levels deep under a_dir, as list of tuples (b,c,d)

load3DirLevels :: FilePath -> IO [(String,String,String)]
do
bs <- getDirectoryContents a_dir

foldM (\tups b -> do
cs <- getDirectoryContents (a_dir ++ "/" ++ b)
foldM (\tups' c -> do
ds <- getDirectoryContents (a_dir ++ "/" ++ b
++ "/" ++ c)
foldM (\tups'' d -> do
return \$ (b, c, d) : tups''
) tups' ds
) tups cs
) [] bs

This function isn't so clear at a glance, and yet what it's doing
seems like a pretty common thing to want to do:  are there any library
functions for monads (or IO in particular) that make this sort of thing
easier, or should I to try and write my own function?  Looks not too
difficult to write but I think I might miss something important if I didn't ask
first...  How would you do it?

Thanks
Steve