代码之家  ›  专栏  ›  技术社区  ›  Drakosha

确定Haskell中是否存在文件列表

  •  4
  • Drakosha  · 技术社区  · 14 年前

    我是个新手,蒙娜兹一家让我很困惑。给出一个文件名列表,我想知道是否所有的文件都存在。

    一般来说,我想做:

    import System.Directory
    allFilesPresent files = foldr (&&) True (map doesFileExist files)
    

    IO Bool 而不是 Bool 参与其中。

    帮助和解释会非常好,谢谢!

    3 回复  |  直到 7 年前
        1
  •  12
  •   sepp2k    14 年前

    你说得对,你的代码不起作用是因为 map doesFileExist files IO Bool 而不是 Bool . 要解决这个问题,你可以使用 mapM map ,这会给你一个 IO [Bool] >>= <- 在一个 do -阻塞然后使用 foldr (&&) 打开包装 [Bool] return 那。结果将是 IO布尔 . 这样地:

    import System.Directory
    allFilesPresent files = mapM doesFileExist files >>=
                            return . foldr (&&) True
    

    或者使用do符号:

    import System.Directory
    allFilesPresent files = do bools <- mapM doesFileExist files
                               return $ foldr (&&) True bools
    

    或使用 liftM Control.Monad :

    allFilesPresent files = liftM (foldr (&&) True) $ mapM doesFileExist files
    

    或使用 <$> Control.Applicative

    allFilesPresent files = foldr (&&) True <$> mapM doesFileExist files
    
        2
  •  6
  •   John Millikin    14 年前

    doesFileExist "foo.txt" 是一个 IO Bool

    你走对了 map doesFileExist files --此表达式将返回 [IO Bool] ,或依赖于世界的表达式列表。实际上需要的是 IO 包含布尔列表的表达式。你可以用这个 sequence :

    sequence :: Monad m => [m a] -> m [a]
    

    或者,因为你只是在使用序列/映射,所以 mapM 帮助函数:

    mapM :: Monad m => (a -> m b) -> [a] -> m [b]
    mapM f xs = sequence (map f xs)
    

    让我们回到你的代码。这是一个使用 mapM公司 ,带注释:

    import System.Directory
    
    -- When figuring out some unfamiliar libraries, I like to use type annotations
    -- on all top-level definitions; this will help you think through how the types
    -- match up, and catch errors faster.
    allFilesPresent :: [String] -> IO Bool
    
    -- Because allFilesPresent returns a computation, we can use do-notation to write
    -- in a more imperative (vs declarative) style. This is sometimes easier for students
    -- new to Haskell to understand.
    allFilesPresent files = do
    
        -- Run 'doesFileExist' tests in sequence, storing the results in the 'filesPresent'
        -- variable. 'filesPresent' is of type [Bool]
        filesPresent <- mapM doesFileExist files
    
        -- The computation is complete; we can use the standard 'and' function to join the
        -- list of bools into a single value.
        return (and filesPresent)
    

    allFilesPresent :: [String] -> IO Bool
    allFilesPresent = fmap and . mapM doesFileExist
    
        3
  •  6
  •   Tsuyoshi Ito    14 年前

    请注意,如果您使用 sequence mapM ,您选择不短路;即使其中一个文件不存在,您仍会检查其余文件是否存在。如果您想短路,以下操作有效:

    import System.Directory
    
    andM :: Monad m => [m Bool] -> m Bool
    andM [] =
        return True
    andM (m : ms) = do
        b <- m
        if b then
          andM ms
         else
          return False
    
    allFilesPresent :: [FilePath] -> IO Bool
    allFilesPresent files = andM $ map doesFileExist files
    

    或等同于使用 monad-loops package :

    import System.Directory
    import Control.Monad.Loops
    
    allFilesPresent :: [FilePath] -> IO Bool
    allFilesPresent = allM doesFileExist