【问题标题】:Handle is semi-closed error in Haskell?Haskell中的句柄是半封闭错误?
【发布时间】:2016-08-04 19:39:31
【问题描述】:

我在 GHCI 中遇到此错误:

*** Exception: <stdin>: hGetLine: illegal operation (handle is semi-closed)

运行这段代码后:

main = do
    interact $ unlines . fmap proccess . take x . lines
    readLn :: IO Int

我很确定原因是take x。有没有更好的方法来读取only x 行输入使用交互interact 只是一个单独的玩家?

【问题讨论】:

  • interact 将标准输入置于半关闭状态。我假设您的函数第一次正常工作,之后的所有其他调用都失败了?关闭并重新打开 GHCi 或编译您的程序并执行它。
  • 没错,之后每次读取stdin 都失败了。
  • 附带说明,除了关闭并重新打开 ghci 之外,是否可以通过其他方式重新打开关闭的标准输入句柄?
  • 正如@RowanBlush 所指出的,stdin 句柄被interact 或读取整个标准输入的任何函数置于半关闭状态。请记住,您的 GHCI 会话基本上是一个大块 - 写 main = getContents >> getContents 同样是无效的。如果您想阅读n 行,只需使用replicateM n getLine{readLn/whatever} - 使用读取所有标准输入的函数之后总是会关闭标准输入。您不能“重新打开”stdin - 它只是底层的 unix 文件描述符。

标签: haskell io handle


【解决方案1】:

interact 无法实现您想要做的事情。在幕后interacthGetContents 声明了stdin 的全部内容。这会将句柄置于“半关闭”状态,阻止您尝试与句柄进行任何进一步的交互,而不是关闭它,因为它的全部输入已经被消耗(懒惰地)。

尝试读取有限的行数——

import Control.Monad (replicateM)

getLines :: Int -> IO [String]
getLines n = replicateM n getLine

【讨论】:

    【解决方案2】:

    从概念上讲,interact 消耗所有的标准输入。所以事后打电话给readLn没有任何意义。

    要仅读取给定数量的行,请使用以下内容:

    import Control.Monad
    
    main = do input <- replicateM 10 getLine
              ...
    

    这里input 将是(确切地说)10 个字符串的列表。

    如果您想减少行数,或者如果您想在遇到特殊情况时停止阅读,事情会变得更加复杂。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-05
      相关资源
      最近更新 更多