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

Posted

技术标签:

【中文标题】Haskell:将文件中的每一行插入到列表中【英文标题】:Haskell: Inserting every line from a file into a list 【发布时间】:2010-09-17 23:05:23 【问题描述】:

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

提前致谢!

【问题讨论】:

【参考方案1】:

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

返回“IO a”类型值的东西;其中“a”类型的值被丢弃(因此“a”通常为“()”) 一个 的左侧 一个 let,它只是为一个值命名

在那个do块中,“hGetLine inh”返回一个“IO字符串”,其中的字符串被提取并命名为inpStr。下一行,因为它既不是 let 也不是

let list' = inpStr:list

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

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

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

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

【讨论】:

【参考方案2】:

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

getLines = liftM lines . readFile

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

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

【讨论】:

在向似乎仍在学习 Haskell 的人解释事情时,我会避免使用(甚至展示)无意义的风格。不想吓到他们 ;-) +1 用于提及readFile。摆脱打开文件/读取行/检测EOF/关闭文件的命令式思维方式,让readFilegetContentsinteract 等函数为您处理这些问题非常有帮助。 “mapM_”是什么意思?我知道“mapM”将一个函数映射到 monad .. 但是带有下划线的那个? @drozzy: mapM_mapM 完全相同,只是它忽略了结果。因此,您无需在 monad 中获取结果列表,而只需在其中 () 即可。因为putStrLn 无论如何都会给IO (),所以mapM 你会得到IO [()]mapM_ 只是把它变成你真正想要的 IO () 我知道,我已经有一段时间了,但只是偶然发现了它。我也是一个haskell初学者并且有一个问题。使用您的代码调用 main 只需将 dictionary.txt 的内容打印到屏幕上。我怎样才能将它们放在一个列表中,以便我能够对该列表执行其他操作? main 的类型为:: IO ()。如何获取字符串列表,其中每个字符串都是一行 dictionary.txt?谢谢

以上是关于Haskell:将文件中的每一行插入到列表中的主要内容,如果未能解决你的问题,请参考以下文章

在 git 中,如何避免将较小的更正合并到在原始内容的每一行之间插入一行新内容的分支中的冲突?

试图让文本文件的每一行成为一个数组列表

用 90 行 Haskell 代码实现 2048 游戏

如何将 csv 文件读入 SWI prolog 中的列表列表,其中内部列表代表 CSV 的每一行?

haskell 列表中的唯一元素

将抽象数据类型保存和加载到 json 文件并从游戏中的文件中读取 Haskell