2013-05-23 2 views
7

Vorrei elencare tutte le sottocartelle di una cartella in Haskell. Ottenere tutti i contenuti delle cartelle è facile, c'è una funzione getDirectoryContents. Ma come li filtro? Dal momento che getDirectoryContents restituisce un IO [FilePath] e filter si aspetta [a], non riesco a mettere questi due direttamente insieme. (. Ovviamente, io sono un pesce fresco con monadi e fare notazione)Come trovo tutte le sottocartelle di una cartella?

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

risposta

7

Il problema non è che getDirectoryContents ha il ritorno tipo IO [FilePath], si ottiene una lista piana di FilePath s legando il risultato,

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

il problema è che il il predicato doesDirectoryExist ha il tipo FilePath -> IO Bool. Per queste cose, non v'è

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

filterM definito Control.Monad, così

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

o, senza legarsi il contenuto della directory a un nome,

getAllFolders path = getDirectoryContents path >>= filterM doesDirectoryExist 

e senza punti :

getAllFolders = getDirectoryContents >=> filterM doesDirectoryExist 
+0

Grazie! C'è un ulteriore problema con percorsi di file relativi/assoluti, ma posso capirlo. – zoul

+2

Questo problema con i percorsi relativi mi fa inciampare costantemente - al punto in cui ho inventato una biblioteca solo per aggirarla! Inoltre, 'getDirectoryContents' restituisce sempre' .' e '..', che è fastidioso. – MathematicalOrchid

+0

'> =>' mmmm. Ci piace '> =>'. – AndrewC

3

assomiglia filterM offerto dal Control.Monad è la risposta:

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

corretto. Puoi anche combinare le ultime due righe in 'filterM doesDirectoryExist allItems', poiché' x <- foo; return x' è lo stesso di solo 'foo'. – hammar

+0

Ottimo, grazie. – zoul