Haskell:如何从一个公共列表中创建文件列表和目录列表

时间:2017-12-11 14:27:09

标签: list file haskell partition io-monad

这是一个新手问题。假设我想将文件和目录列表分成文件列表和目录列表:

getFilesAndDirs :: [FilePath] -> ([FilePath], [FilePath])
getFilesAndDirs paths =
  let ...
  in (dirs, files)

可能这是一个毫无希望的重复,我只是错过了正确的关键词。 做什么(并称之为)的正确方法是什么?

文件和目录随机出现。

3 个答案:

答案 0 :(得分:2)

Data.List包具有partition :: (a -> Bool) -> [a] -> ([a],[a])函数,该函数根据谓词将a列表拆分为两个a列表的元组。

但问题是,当我们检查文件是否是目录时,我们可能会使用isDirectory :: FilePath -> IO Bool,因此我们不能直接将其用作谓词(因为IO Bool不等于{{ 1}})。

我们可以编写自己的Bool,并使用那个:

partitionM

然后我们可以像:

一样使用它
import Data.Bool(bool)
import Data.Foldable(foldrM)

partitionM :: (Foldable t, Monad m) => (a -> m Bool) -> t a -> m ([a], [a])
partitionM p = foldrM (selectM p) ([],[])

selectM :: Monad m => (a -> m Bool) -> a -> ([a], [a]) -> m ([a], [a])
selectM p x (ts,fs) = p x >>= return . bool (ts, x:fs) (x:ts,fs)

请注意它是import System.Directory(isDirectory) getFilesAndDirs :: [FilePath] -> IO ([FilePath], [FilePath]) getFilesAndDirs = partitionM isDirectory,因为我们需要执行I / O以检查路径是否确实是目录(而不是文件)。

答案 1 :(得分:2)

您可以使用do符号来编排程序中不纯的部分,然后使用内置(纯)函数(如partition)来完成实际工作。这是一个例子:

module Q47755054 (getFilesAndDirs) where

import Data.List (partition)
import Data.Bifunctor (bimap)
import System.Directory (doesDirectoryExist)

tagPath :: FilePath -> IO (FilePath, Bool)
tagPath path = do
  isDirectory <- doesDirectoryExist path
  return (path, isDirectory)

getFilesAndDirs :: [FilePath] -> IO ([FilePath], [FilePath])
getFilesAndDirs paths = do
  taggedPaths <- mapM tagPath paths
  return $ bimap (fmap fst) (fmap fst) $ partition snd taggedPaths

请注意,这会使用内置的mapM函数来获取不纯的值列表(IO [(FilePath, Bool)]),但由于do语法和<-绑定,taggedPaths'看起来像纯值([(FilePath, Bool)]),因此您可以将其传递给partition

另外请注意,tagPath只是模块级辅助函数,不会被模块导出。

答案 2 :(得分:0)

module SeparateFiles where
    import Data.String
    import System.FilePath.Posix


    type Path = FilePath
    getFilesAndDirs :: Path -> [(Path,Path)]
    getFilesAndDirs path = [splitFileName path]

据我所知,您希望将FilePath提取拆分为文件和目录。我为你提供了一个很短的例子。