2013-05-23 4 views
7

Я хотел бы перечислить все подпапки папки в Haskell. Получение всего содержимого папки легко, есть функция getDirectoryContents. Но как их фильтровать? Поскольку getDirectoryContents возвращает IO [FilePath], а filter ожидает [a], я не могу поместить эти два непосредственно вместе. (. Очевидно, я свежая рыба с монадами и делать-обозначение)Как найти все подпапки папки?

getAllFolders :: FilePath -> IO [FilePath] 
getAllFolder path = do 
    allItems <- getDirectoryContents path 
    -- now what? the predicate is doesDirectoryExist 

ответ

7

Проблема заключается не в том, что getDirectoryContents имеет возврат тип IO [FilePath], вы получите простой список FilePath с связыванием результата,

getAllFolders path = do 
    contents <- getDirectoryContents path 
    -- do something with contents now, it's a plain [FilePath] 

проблема заключается в том, что предикат doesDirectoryExist имеет тип FilePath -> IO Bool. Для таких вещей есть

ghci> :t Control.Monad.filterM 
Control.Monad.filterM :: Monad m => (a -> m Bool) -> [a] -> m [a] 

filterM определена в Control.Monad, так

getAllFolders path = do 
    contents <- getDirectoryContents path 
    filterM doesDirectoryExist contents 

или без связывания содержимого каталога с именем,

getAllFolders path = getDirectoryContents path >>= filterM doesDirectoryExist 

и точка свободной :

getAllFolders = getDirectoryContents >=> filterM doesDirectoryExist 
+0

Спасибо! Есть дополнительная проблема с относительными/абсолютными файловыми путями, но я могу понять это. – zoul

+2

Эта проблема с относительными путями постоянно меня отключает - до такой степени, что я придумал библиотеку, чтобы обойти ее! Кроме того, 'getDirectoryContents' всегда возвращает' .' и '..', что раздражает. – MathematicalOrchid

+0

'> =>' мммм. Нам нравится '> =>'. – AndrewC

3

Похож filterM, предлагаемое Control.Monad ответ:

getAllFolders :: FilePath -> IO [FilePath] 
getAllFolders path = do 
    allItems <- getDirectoryContents path 
    justFolders <- filterM doesDirectoryExist allItems 
    return justFolders 
+0

Правильно. Вы также можете комбинировать последние две строки только в 'filterM doDirectoryExist allItems', так как' x <- foo; return x' - это то же самое, что и 'foo'. – hammar

+0

Отлично, спасибо. – zoul