【问题标题】:Haskell Compiled IO-Action order and Flushing [duplicate]Haskell 编译的 IO-Action 顺序和刷新 [重复]
【发布时间】:2015-02-04 02:56:53
【问题描述】:

我在已编译的 Haskell 代码中遇到了 IO 的奇怪行为。这是发生了什么:

-- MyScript.hs
main = do
    putStr "Enter your name: "
    a <- getLine
    putStrLn (a ++ " - that's a nice name!")

我通过调用main 在 GHCi 中运行它,它可以按预期工作,首先打印Enter your name:,然后再做任何事情。然而,当我用 GHC 编译它(有和没有--make)时,它首先提示输入一行,然后 然后 立即打印所有内容,如下所示:

$ ./MyScript
Jimmy Johnson
Enter your name: Jimmy Johnson - That's a nice name!

为了澄清,我希望它按以下顺序发生:

$ ./MyFixedScript
Enter your name: Jimmy Johnson
Jimmy Johnson - That's a nice name!

有人可以解释为什么会这样,以及如何按照我期望的方式对 IO 进行排序。

另请注意,我已尝试将do 语句的第一行更改为_ &lt;- putStr "Enter your name: ",但这仍然不起作用。

【问题讨论】:

  • 这是由于缓冲而不是 io 操作的排序。

标签: haskell io stdout monads


【解决方案1】:

IO 操作以正确的顺序发生,问题在于输入和输出管道的工作方式。字符串"Enter your name: "putStrgetLine 之前写入输出缓冲区,但缓冲区不一定被刷新。在putStr 之后添加hFlush stdout 将刷新缓冲区。

import System.IO

-- MyScript.hs
main = do
    putStr "Enter your name: "
    hFlush stdout
    a <- getLine
    putStrLn (a ++ " - that's a nice name!")

【讨论】:

  • 哇,我原以为可能是这样,但我不相信 Haskell 真的会遵守像刷新标准输出这样的有状态的事情......
  • @AJFarmar:在这种情况下,Haskell 只是为您提供了与其他编程语言相同的底层管道抽象的非常直接的接口。由于它隐藏在 IO 中,因此它可以准确地复制行为。
  • 我想 GHCi 会自动刷新?
【解决方案2】:

我今天也遇到了同样的问题,当我使用putStrLn 时它似乎运行良好,但当我将其更改为putStr 时它停止了。正如其他人所说,它与 Haskell 或 GHC 无关,而是如何刷新 IO。根据System.IOdocumentation有3种缓冲模式:

  • 行缓冲:每当输出换行符、缓冲区溢出、发出 System.IO.hFlush 或句柄关闭时,都会刷新整个输出缓冲区。
  • 块缓冲:当整个缓冲区溢出、发出 System.IO.hFlush 或句柄关闭时,整个缓冲区都会被写出。
  • no-buffering:输出立即写入,从不存储在缓冲区中。

默认的缓冲模式据说是依赖于系统的,但似乎普通程序处于line-buffering模式,而GHCI处于no-buffering模式。这解释了因为使用putStrLnputStr 是否会刷新。

要解决您的问题,您可以使用 hFlush stdout 来刷新显式(请参阅 Cirdec 答案)或通过执行 hSetBuffering stdout NoBuffering 更改一次缓冲模式。显然NoBuffering 模式不是最佳的,但对于小型玩具程序来说可能已经足够了。

【讨论】:

  • hSetBuffering 的句柄是第一个参数。 hSetBuffering :: Handle -&gt; BufferMode -&gt; IO () 所以在stdout 上设置NoBuffering 将是hSetBuffering stdout NoBuffering
猜你喜欢
  • 1970-01-01
  • 2016-03-04
  • 2012-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-12
  • 2011-07-10
  • 1970-01-01
相关资源
最近更新 更多