IO发生无序使用函数getline和putStr时(IO happens out of order

2019-06-18 18:25发布

我是一个Haskell初学者,我刚开始换我周围的单子头,但我真的不明白呢。 我正在写一个游戏,包括要求用户输入和应对的。 这里是我的功能的简化版本:

getPoint :: IO Point
getPoint = do
    putStr "Enter x: "
    xStr <- getLine
    putStr "Enter y: "
    yStr <- getLine
    return $ Point (read xStr) (read yStr)


completeUserTurn :: (Board, Player) -> IO (Board, Player)
completeUserTurn (board, player) = do
    putStr $ "Enter some value: "
    var1 <- getLine
    putStr $ "Enter another value: "
    var2 <- getLine
    putStr $ "Enter a point this time: "
    point <- getPoint
    if (... the player entered legal values ...) then do
        putStr $ "This is what would happen if you did that: {stuff} do you want to do that? (y/n) "
        continue <- getLine
        if continue == "y" then
            return (...updated board..., ...updated player...)
        else
            completeUserTurn (board, player)
    else do
        putStr "Invalid Move!\n"
        completeUserTurn (board, player)

发生了什么事是,提示将出现无序与应该提示之前要显示的文本。

下面是我之后编译上面的代码中所发生的事情的一个例子:

1
输入一些值:请输入一个值:2
3
4
输入一个点这段时间:输入X:输入y:Y
它是否正确? (Y / N):

大胆的是我在打字的东西。

很显然,我有一些主要的概念上的错误,但我不知道是什么。 需要注意的是它的工作原理正确解释和编译时失败。

Answer 1:

正如迈克尔说,这个问题是缓冲。 默认情况下,输出缓冲,直到你打印一个换行符(或直到缓冲区已满,如果你有很长的线),所以你会经常看到试图做同样的线路使用提示,当这个问题putStr像你这样做。

我建议定义一个小助手功能,像这样采取做冲洗你的护理:

import System.IO

prompt :: String -> IO String
prompt text = do
    putStr text
    hFlush stdout
    getLine

现在,你可以简单地做

getPoint = do
    xStr <- prompt "Enter x: "
    yStr <- prompt "Enter y: "
    return $ Point (read xStr) (read yStr)


Answer 2:

该IO正在发生的事情以正确的顺序。 问题是缓冲。 如果你把每putStr后冲洗(flush)标准输出,它应该工作的期待。 你需要导入hFlushstdoutSystem.IO



Answer 3:

这个问题是不是与运营中的IO代码的顺序。 问题是输入和输出是默认使用标准输入和stdout时缓冲。 这增加IO的性能的应用程序,但可能会导致操作出现在标准输入和stdout用于不按顺序发生。

有两个解决办法。 您可以使用hFlush方法强制手柄(或标准输入和标准输出)被刷新。 例如hFlush stdouthFlush stdin 。 一种更简单的解决方案(其用于交互式应用程序正常工作)是完全禁用缓冲。 您可以通过调用方法做到这一点hSetBuffering stdout NoBufferinghSetBuffering stdin NoBuffering您启动程序之前(即把这些线在你的主要方法。



文章来源: IO happens out of order when using getLine and putStr