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

提前致谢!

有帮助吗?

解决方案

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

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

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

let list' = inpStr:list

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

更改以下行以使用“list'”而不是“list”(从而将新列表传递给它)。该行(递归地)调用主循环,主循环将再读取一行,调用自身,等等。读取整个文件后,它会返回“IO()”类型的内容。这个“IO()”将返回到loadNums处的do块。恭喜,您刚刚创建了一个列表,其中包含从文件中按相反顺序读取的行(因为您附加到列表的头部),然后没有对其执行任何操作。

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

剩下的就留给读者作为练习。

其他提示

除非这是作业或其他东西,否则没有理由使用这么多的努力。重用是懒惰的!

getLines = liftM lines . readFile

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top