如何对多个文件使用Haskell的readFile函数

8cdiaqws  于 2023-03-30  发布在  其他
关注(0)|答案(2)|浏览(140)

我对IO有一点了解。我知道你可以使用readFile来获取文件的内容。例如:

main = do
    let inputFilePath = "C:\\Haskell\\myawesomeprogram\\files\\a.txt"
    content <- readFile inputFilePath
    print content

调用程序:

> runghc myawesomeprogram
"AAA"

太棒了,这很有效!现在我想从多个文件中读取内容。我尝试了这样的方法:

files = ["C:\\Haskell\\myawesomeprogram\\files\\a.txt", "C:\\Haskell\\myawesomeprogram\\files\\b.txt","C:\\Haskell\\myawesomeprogram\\files\\c.txt"]

main :: IO ()
main = do
    filesContent <- readFiles files
    print filesContent

readFiles (x:xs) = do 
    content <- readFile x
    content : readFiles xs

这将给予以下错误消息:

myawesomeprogram.hs:6:21: error:
    * Couldn't match type `[]' with `IO'
      Expected type: IO String
        Actual type: [String]
    * In a stmt of a 'do' block: filesContent <- readFiles files
      In the expression:
        do filesContent <- readFiles files
           print filesContent
      In an equation for `main':
          main
            = do filesContent <- readFiles files
                 print filesContent
  |
6 |     filesContent <- readFiles files
  |                     ^^^^^^^^^^^^^^^

myawesomeprogram.hs:9:1: error:
    Couldn't match type `IO' with `[]'
    Expected type: [FilePath] -> [String]
      Actual type: [FilePath] -> IO String
  |
9 | readFiles (x:xs) = do
  | ^^^^^^^^^^^^^^^^^^^^^^^...

myawesomeprogram.hs:11:5: error:
    * Couldn't match type `[]' with `IO'
      Expected type: IO String
        Actual type: [String]
    * In a stmt of a 'do' block: content : readFiles xs
      In the expression:
        do content <- readFile x
           content : readFiles xs
      In an equation for `readFiles':
          readFiles (x : xs)
            = do content <- readFile x
                 content : readFiles xs
   |
11 |     content : readFiles xs
   |     ^^^^^^^^^^^^^^^^^^^^^^

我正在做一件错事,然而,我看不出有什么方法可以把它做对。你能把它做对吗?

lrl1mhuk

lrl1mhuk1#

readFiles xs不是一个列表,所以你不能在它前面加上一个元素,相反,它是一个 action,当执行时,它会产生一个列表。
更具体地说,readFiles xs的类型是IO [String]IO是可执行操作的类型),而列表的类型是[String]。这就是错误消息告诉你的:无法将类型IO [String][String]匹配。
因此,要获得列表,必须执行操作,就像执行readFile一样

readFiles (x:xs) = do
    content <- readFile x
    theRest <- readFiles xs
    pure (content : theRest)

还要注意readFiles不知道当它的参数是一个空列表时该怎么做,你应该在编译时得到一个警告,如果你不修复它,你会在运行时崩溃。
要解决这个问题,只需为空列表添加一个等式:

readFiles [] = pure []
readFiles (x:xs) = do
    content <- readFile x
    theRest <- readFiles xs
    pure (content : theRest)
but5z9lq

but5z9lq2#

如果你想对列表中的每一项做些什么,你可以使用map
然而,map readFile files在一个列表上只给你一个将产生它们的内容的动作列表,而不是它们的内容列表。然后有sequence将采取一个动作列表,并将其转换为产生结果列表的操作。Map操作并对其进行排序是一个足够频繁的问题,因此将其缩短为mapM。它位于Control.Monad
您需要的代码如下所示:

main :: IO ()
main = do
    filesContent <- mapM readFile files
    print filesContent

请不要滚动自己的函数来执行此操作。

相关问题