11

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

提前致谢!

4

2 回答 2

15

除非这是为了家庭作业或其他事情,否则没有理由花费这么多精力。重用是懒惰的!

getLines = liftM lines . readFile

main = do
    list <- getLines "dictionary.txt"
    mapM_ putStrLn list

但是由于您似乎仍在学习 Haskell,因此了解 CesarB 所写的内容对您来说很重要。

于 2008-10-19T01:04:47.533 回答
14

在发生错误的行中,Haskell 期待“IO a”,但您给它一个 []。简化了很多事情,在 IO monad 的 do 块上,每一行都是:

  • 返回“IO a”类型的值的东西;其中“a”类型的值被丢弃(因此“a”通常是“()”)
  • 一个 <- 表达式,它做同样的事情,但不是丢弃“a”类型的值,而是将它的名称放在 <- 的左侧
  • 一个 let,它只不过是给一个值一个名字

在那个 do 块中,“hGetLine inh”返回一个“IO 字符串”,其中的字符串被提取并命名为 inpStr。下一行,因为它既不是 let 也不是 <-,应该有一个类型“IO a”,它没有(从而导致编译器错误)。既然你已经有了字符串,你可以做的是让:

let list' = inpStr:list

这将创建一个由字符串和原始列表组成的新列表,并将其命名为“list”。

更改以下行以使用“list”而不是“list”(从而将新列表传递给它)。该行调用(递归)主循环,它将再读取一行,调用自身,依此类推。读取整个文件后,它会返回“IO()”类型的东西。此“IO()”将返回到 loadNums 处的 do 块。恭喜,您刚刚创建了一个列表,其中包含从文件中读取的行,以相反的顺序(因为您附加到列表的头部),然后什么也没做。

如果你想对它做点什么,把“return()”改成“return list”;return 将生成一个类型为“IO [String]”的值,其中包含列表(return 只是封装该值),您可以使用 <- 语法在 loadNums 处提取该值。

其余的留给读者作为练习。

于 2008-10-19T00:46:23.203 回答