Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I find all subfolders of a folder?

Tags:

io

haskell

monads

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
like image 438
zoul Avatar asked May 23 '13 14:05

zoul


2 Answers

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
like image 171
Daniel Fischer Avatar answered Sep 28 '22 11:09

Daniel Fischer


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
like image 20
zoul Avatar answered Sep 28 '22 10:09

zoul