2013-05-23 41 views
7

Tôi muốn liệt kê tất cả thư mục con của một thư mục trong Haskell. Bắt tất cả nội dung thư mục thật dễ dàng, có chức năng getDirectoryContents. Nhưng làm cách nào để lọc chúng? Vì getDirectoryContents trả lại một số IO [FilePath]filter mong đợi [a], tôi không thể đặt hai trực tiếp đó lại với nhau. (. Rõ ràng, tôi là một con cá tươi với monads và làm-ký hiệu)Làm cách nào để tìm tất cả thư mục con của một thư mục?

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

Trả lời

7

Vấn đề không phải là getDirectoryContents có sự trở lại loại IO [FilePath], bạn sẽ có được một danh sách đơn giản của FilePath s bằng cách gắn kết quả,

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

vấn đề là các biến vị ngữ doesDirectoryExist có loại FilePath -> IO Bool. Đối với những thứ như vậy, có

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

filterM quy định tại Control.Monad, vì vậy

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

hay, mà không ràng buộc các nội dung của thư mục với một tên,

getAllFolders path = getDirectoryContents path >>= filterM doesDirectoryExist 

và point-miễn phí :

getAllFolders = getDirectoryContents >=> filterM doesDirectoryExist 
+0

Cảm ơn bạn! Có một vấn đề khác với các tệp tương đối/tuyệt đối, nhưng tôi có thể hiểu được điều đó. – zoul

+2

Vấn đề đó với các đường dẫn tương đối liên tục vấp ngã tôi - đến mức tôi đã phát minh ra một thư viện chỉ để giải quyết nó! Ngoài ra, 'getDirectoryContents' luôn trả về' .' và '..', điều này gây phiền toái. – MathematicalOrchid

+0

'> =>' mmmm. Chúng tôi thích '> =>'. – AndrewC

3

Hình như filterM được cung cấp bởi Control.Monad là câu trả lời:

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

đúng. Bạn cũng có thể kết hợp hai dòng cuối cùng thành 'filterM doesDirectoryExist allItems', vì' x <- foo; return x' giống như 'foo'. – hammar

+0

Tuyệt vời, cảm ơn bạn. – zoul

Các vấn đề liên quan