代码之家  ›  专栏  ›  技术社区  ›  Alexey Orlov

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

  •  3
  • Alexey Orlov  · 技术社区  · 7 年前

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

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

    可能这是一个无望的复制,我只是错过了正确的关键字。 这样做(并称之为)的正确方式是什么?

    文件和目录随机出现。

    3 回复  |  直到 7 年前
        1
  •  2
  •   willeM_ Van Onsem    7 年前

    这个 Data.List 包具有 partition :: (a -> Bool) -> [a] -> ([a],[a]) 函数,用于拆分 a s转换为两个列表的元组 s基于谓词。

    然而,问题是,当我们检查文件是否是目录时,我们可能会使用 isDirectory :: FilePath -> IO Bool 因此,我们不能直接将其用作谓词(因为 IO Bool 不等于 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

    请注意,它是 IO ([FilePath], [FilePath]) ,因为我们需要执行I/O来检查路径是否确实是目录(而不是文件)。

        2
  •  2
  •   Mark Seemann    7 年前

    您可以使用 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)] ),但由于 语法和 <- 结合 taggedPaths “看起来”像一个纯值( [(FilePath, Bool)] ),因此您可以将其传递给 隔断 .

    此外,请注意 tagPath 只是模块级的辅助函数,而不是由模块导出。

        3
  •  0
  •   Imaddin Ahmed Mohamed    7 年前
    module SeparateFiles where
        import Data.String
        import System.FilePath.Posix
    
    
        type Path = FilePath
        getFilesAndDirs :: Path -> [(Path,Path)]
        getFilesAndDirs path = [splitFileName path]
    

    我知道您想将文件路径拆分为文件和目录。我给你举一个非常简短的例子。