我目前正在与Haskell合作,并发现自己遇到了一些麻烦。我应该在“dictionary.txt”文件中读取并插入列表中的每一行,但我似乎无法这样做。我有这个代码:
main = do
let list = []
loadNums "dictionary.txt" list
loadNums location list = do
inh <- openFile location ReadMode
mainloop inh list
hClose inh
mainloop inh list = do
ineof <- hIsEOF inh
if ineof
then return ()
else do
inpStr <- hGetLine inh
inpStr:list
mainloop inh list
它应该得到每一行(我知道它确实得到每一行,因为用“putStrLn inpStr”替换“inpStr:list”正常工作,显示所有行),并将其插入列表但我得到以下错误:
Couldn't match expected type `IO' against inferred type `[]'
可能是因为hGetLine不是一个字符串,而是一个IO字符串,我不知道如何处理以获得一个正确的字符串,我可以在我的列表中插入。我不知道如何解决这个问题,或者问题究竟是什么,但如果有人知道如何正确地将文件中的每一行都放入列表中,我会很感激。
提前致谢!
答案 0 :(得分:15)
除非这是作业或其他东西,否则没有理由使用这么多的努力。重用是懒惰的!
getLines = liftM lines . readFile
main = do
list <- getLines "dictionary.txt"
mapM_ putStrLn list
但是,由于您似乎仍在学习Haskell,因此了解CesarB编写的内容非常重要。
答案 1 :(得分:14)
在发生错误的行中,Haskell期待“IO a”,但是你给它一个[]。在IO monad的do块上简化了很多事情,每一行都是:
在该块中,“hGetLine inh”返回“IO String”,并且提取其中的String并给出名称inpStr。下一行,因为它既不是let也不是&lt; - ,应该有一个类型“IO a”,它不会(因此导致编译器错误)。你可以做的,因为你已经有了String,是一个let:
let list' = inpStr:list
这将创建一个新的列表,其中包含String后跟原始列表,并为其命名为“list”。
更改以下行以使用“list”而不是“list”(从而将新列表传递给它)。该行调用(递归)mainloop,它将读取另一行,调用自身,依此类推。读完整个文件后,它将返回“IO()”类型的内容。这个“IO()”将返回到loadNums的do块。恭喜你,你刚刚创建了一个列表,其中包含从文件中读取的行,顺序相反(因为你附加到列表的头部),然后对它没有任何作用。
如果您想对此做些什么,请将“return()”更改为“return list”; return将生成一个类型为“IO [String]”的值,其中包含列表(return只会封装该值),您可以使用&lt; - syntax在loadNums中提取该值。
其余部分留给读者练习。