Haskell IO - hGetContents: 非法操作(句柄已关闭)

9

我正在尝试理解Haskell IO,但stdin的这个特性最终让我感到困惑:

当我尝试使用一些函数,比如getContents,例如:

let main = do x<-getContents; putStrLn x

I get the following error:

hGetContents: illegal operation (handle is closed)

我该如何使用这个函数进行IO操作呢?有没有什么解决方法,或者我应该寻找另一个类似的IO函数呢?

3个回答

9

getContents == hGetContents stdin。实际上,hGetContents 标记其句柄(半)关闭,这意味着任何尝试再次从标准输入读取的操作都会失败。

请查看使用 getContents 后Haskell 用户指南中的说明。


这是正确的,因为即使是 Haskell 也无法改变您在键盘上输入的内容只能被读取一次的事实。 - Ingo

6
我建议您研究另一种方法。使用 getContents 和类似操作存在一些固有问题:
  1. 您可能会有一个无效的句柄 - 一个已经关闭的句柄。这在大多数语言中很常见,但我们可以做得更好。理想情况下,一旦我们关闭句柄,就应该确保我们不能再使用它。
  2. getContents 是一种惰性 IO,这意味着(除了其他问题之外):
    • 我们几乎无法控制何时(如果)关闭句柄
    • 当我们处理由 getContents 返回的字符串时,数据使用惰性 IO 操作读取。这意味着在纯计算内部,我们可能会遇到 IO 效果和错误。

一个更安全的替代方案是使用另一个概念,称为迭代器、管道或传送带。这个想法是你将你的组件描述为读取一些输入数据和/或写输出,然后将它们组合在一起。这使你能够编写非常健壮和优雅的代码。


TBH,这并不是“更好”,因为它导致了控制的反向。 - RandomB

5

这在正常操作中不会出现

如果你试着在ghci中使用getContents,就像你似乎正在做的那样,第二次使用它时就会发生这种情况。第一次调用会将句柄设置为(半)关闭状态,所有后续尝试使用它的操作都将失败。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接