I’d like to enumerate all subfolders of a folder in Haskell. Getting all folder contents is easy, there’s a getDirectoryContents
function. But how do I filter them? Since getDirectoryContents
returns a IO [FilePath]
and filter
expects [a]
, I can’t put those two directly together. (Obviously, I’m a fresh fish with monads and do-notation.)
getAllFolders :: FilePath -> IO [FilePath]
getAllFolder path = do
allItems <- getDirectoryContents path
-- now what? the predicate is doesDirectoryExist
The problem is not that getDirectoryContents
has the return type IO [FilePath]
, you get a plain list of FilePath
s by binding the result,
getAllFolders path = do
contents <- getDirectoryContents path
-- do something with contents now, it's a plain [FilePath]
the problem is that the predicate doesDirectoryExist
has the type FilePath -> IO Bool
. For such things, there is
ghci> :t Control.Monad.filterM
Control.Monad.filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
filterM
defined in Control.Monad
, so
getAllFolders path = do
contents <- getDirectoryContents path
filterM doesDirectoryExist contents
or, without binding the contents of the directory to a name,
getAllFolders path = getDirectoryContents path >>= filterM doesDirectoryExist
and point-free:
getAllFolders = getDirectoryContents >=> filterM doesDirectoryExist
Looks like filterM
offered by Control.Monad
is the answer:
getAllFolders :: FilePath -> IO [FilePath]
getAllFolders path = do
allItems <- getDirectoryContents path
justFolders <- filterM doesDirectoryExist allItems
return justFolders
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With