从文件中读取 3 行 - Haskell

Reding 3 lines from file - Haskell

我正在编写 Haskell 程序。稍后会有更多高级功能,但现在我还停留在读取文件上。我知道有很多关于它的线程,但据我所知,所有解决方案都是基于循环的。我需要从 3 行的 txt 文件中读取。并将这 3 行的内容保存在 3 个单独的变量中以供进一步使用,因此基于循环的解决方案不仅不是必需的,而且还有问题(保存到 3 个不同的变量中)。我搜索了一下,找到了一些例子,试图从中构建一些东西,但是这种语言看起来很奇怪我不明白为什么有些修改有效而有些无效。

首先,工作代码:

import System.IO

main :: IO ()
main = do 
   inh <- openFile "input.txt" ReadMode
   outh <- openFile "output.txt" WriteMode
   mainloop inh outh
   hClose inh
   hClose outh

mainloop :: Handle -> Handle -> IO ()
mainloop inh outh = do 
inp1 <- hGetLine inh
inp2 <- hGetLine inh
inp3 <- hGetLine inh
putStrLn (inp3)

此代码首先读取文件中的第二行,然后是第三行,将每一行保存到各自的变量中,然后将 inp3 显示在屏幕上。事情是这样的,我不需要打印它只是将它保存到 3 个变量中以供进一步使用,但是如果没有打印行,程序将无法运行,编译器说 "the last statement in do block must be an expression"。但是,如果我想打印更多行只是为了查看读取是否正常工作并添加更多 putStrLn(对于 inp1 和 inp2),它将无法编译。例如,在获取 inp1 的行之后添加行 "putStrLn (inp1)" 后,它不会编译并显示“patter putStrLn 中的解析错误,可能是由于缺少 'do'?我只是开始 wwith Haskell 所以这可能是显而易见的,但我不知道是什么。

还有第二个问题。该程序从 input.txt 读取。我希望它询问姓名,等待人输入然后打开它。我认为它会像

putStrLn "Type name"
name <- getLine
inh <- openFile name ReadMode    

但它也不起作用。我将非常感谢任何可以帮助我的输入。奇怪的是 http://en.wikibooks.org/wiki/Haskell/Libraries/Solutions/IO 中给出的例子 正在使用类似的东西并且编译没有任何问题,但我的不会。有什么建议吗?

所以问题是 GHC 拒绝编译 :

mainloop :: Handle -> Handle -> IO ()
mainloop inh outh = do 
  inp1 <- hGetLine inh
  inp2 <- hGetLine inh
  inp3 <- hGetLine inh

对吗?

这实际上是非常合理的,你在用(坏的)命令式的方式思考,就好像你的 inp# 是全局变量,你可以在 mainloop 中初始化它们后在另一个函数中使用...但事实并非如此:inp1、inp2 和 inp3 只是引入的本地绑定,只能在 mainloop 中的这个 do-block 中使用,所以当最后一行是 :

inp3 <- hGetLine inh

很明显,这是一个错误,因为您将无法在任何地方使用此 inp3(您在 do 块的末尾),这就是为什么 GHC 告诉您 do 的最后一行-block 应该是像 putStrLn inp3 这样的表达,而不是矫揉造作。

现在应该清楚你的函数 mainloop 实际上读取了这些行但立即丢失了它们,如果你想在调用者中使用它们你必须 return 它们与 return (inp1, inp2, inp3) 例如(这是一个表达方式,因此您的 GHC 会对您的 do-block 感到满意)。当然,Haskell 是抽象之王,所以重复同一行 3 次并为临时变量赋予 3 个无用的名称有点令人厌恶......其他建议无需重复即可执行相同的操作并且不必发明无用的名称将是:

mainLoop inh = liftA3 (,,) a a a where a = hGetLine inh

这将 return 三胞胎或 :

mainLoop inh = replicateM 3 (hGetLine inh)

这将 return 一个包含 3 个元素的列表...但在这一点上我可能不会只为 [l1,l2,l3] <- replicateM 3 (hGetLine inh).

创建一个函数