从文件中读取3行 - Haskell

时间:2015-01-17 21:23:38

标签: file haskell io

我正在写一个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个变量以供进一步使用,但如果没有打印行,程序就无法运行,编译器说“do块中的最后一个语句必须是表达式”。但是,如果我想打印更多行只是为了查看读取是否正常工作并添加更多putStrLn(对于inp1和inp2)它将无法编译。例如,在获取inp1的行之后添加行“putStrLn(inp1)”之后,它将无法编译并说“在putTtrLn中的解析错误,可能是由于缺少'do'引起的?我只是用Haskell打开了所以它可能是显而易见的,但我不知道是什么。

还有第二个问题。该程序从input.txt读取。我想要它的名字,等待人打字,然后打开它。我认为它会像

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

但它也不起作用。我将非常感谢任何可以帮助我的意见。在http://en.wikibooks.org/wiki/Haskell/Libraries/Solutions/IO给出的例子中奇怪得多 正在使用类似的东西,它编译没有任何问题,但我的不会。任何sugestions?

1 个答案:

答案 0 :(得分:1)

所以问题是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-block的末尾),这就是为什么GHC会告诉你do-block的最后一行应该是putStrLn inp3之类的表达而不是矫揉造作。

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

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

将返回三元组或:

mainLoop inh = replicateM 3 (hGetLine inh)

将返回3个元素的列表......但此时我可能不会仅为[l1,l2,l3] <- replicateM 3 (hGetLine inh)创建函数。