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 FilePaths 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