【问题标题】:Batch modify files Haskell批量修改文件 Haskell
【发布时间】:2015-07-08 10:17:56
【问题描述】:

我正在尝试创建一个程序,为目录(及其子目录)中的每个文件添加一个简单的文本标题。我需要使用 ghc 的内置函数来执行此操作(我无法访问 cabal)。

函数的类型签名是

getRecursiveContents :: FilePath -> IO [FilePath]

addHeaderToFile :: String -> FilePath -> IO ()

这些都可以独立工作,但由于类型的原因,我很难将这两个函数结合使用。我认为使用地图是正确的方法,但到目前为止我还没有成功。

addHeaderToMultiple :: String -> IO [FilePath] -> IO ()
addHeaderToMultiple header files = map (addHeaderToFile header) files

我知道由于使用的类型,这将不起作用,但我还没有找到解决方法。

【问题讨论】:

  • 看看mapM_ :: Monad m => (a -> m b) -> [a] -> m ()

标签: file haskell io


【解决方案1】:

首先运行生成文件列表的 IO 操作:

addHeaderToMultiple :: String -> IO [FilePath] -> IO ()
addHeaderToMultiple header files = do
   -- files has type IO [FilePath]
   paths <- files
   -- paths has type [FilePath], so we can map over that
   map (addHeaderToFile header) paths
   -- this produces [IO ()], which is not IO ()

我们在最后一行遇到了一个问题,它构建了一个 IO 操作列表而不是运行它们。我们可以使用辅助函数:

runInSequence :: [IO ()] -> IO ()
runInSequence []     = return ()  -- nothing to do
runInSequence (a:as) = a >> runInSequence as

可以简化为

runInSequence = foldr (>>) (return ())

实际上,已经有一个库函数可以做到这一点:它被称为sequence_。我们的代码现在变成了

import Control.Monad
addHeaderToMultiple header files = do
   paths <- files
   sequence_ (map (addHeaderToFile header) paths)
   -- this produces IO (), so it's OK

组合sequence_ (map ... 也有自己的库函数,称为mapM_

addHeaderToMultiple header files = do
   paths <- files
   mapM_ (addHeaderToFile header) paths

这可以直接使用&gt;&gt;= 进一步细化

addHeaderToMultiple header files =
   files >>= mapM_ (addHeaderToFile header)

【讨论】:

  • 效果很好,也感谢您解释了沿途的步骤,这使它更容易理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-31
  • 1970-01-01
  • 2022-08-14
  • 2016-04-17
  • 2017-02-15
  • 2020-10-21
相关资源
最近更新 更多