我对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
| ^^^^^^^^^^^^^^^^^^^^^^
我做错了什么,但是,我找不到正确的方法。你能用正确的方法吗?
readFiles xs
不是一个列表,因此不能在其中预先添加项目。相反,它是一个操作,执行时会生成一个列表。
更具体地说,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)
如果您想对列表中的每一项都做些什么,可以使用map
。
但是,列表上的map readFile files
只会为您提供一个将产生其内容的操作列表,而不是一个内容列表。然后是sequence
,它将采取一系列行动,并将其转化为一个行动,产生一系列行动的结果。映射一个动作并对其进行排序是一个非常常见的问题,因此它被缩短为mapM
。它位于Control.Monad
。
你想要的代码是这样的:
main :: IO ()
main = do
filesContent <- mapM readFile files
print filesContent
请不要滚动您自己的函数来执行此操作。