Haskell:将文件中的每一行插入到列表中

时间:2008-10-18 23:57:30

标签: file haskell input io

我目前正在与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字符串,我不知道如何处理以获得一个正确的字符串,我可以在我的列表中插入。我不知道如何解决这个问题,或者问题究竟是什么,但如果有人知道如何正确地将文件中的每一行都放入列表中,我会很感激。

提前致谢!

2 个答案:

答案 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块上简化了很多事情,每一行都是:

  • 返回“IO a”类型值的东西;其中“a”类型的值被丢弃(因此“a”通常是“()”)
  • 一个&lt; - 表达式,它执行相同的操作,但不是丢弃“a”类型的值,而是在&lt; -
  • 左侧给出名称
  • 一个let,它只是给一个值命名

在该块中,“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中提取该值。

其余部分留给读者练习。