为什么我的IO没有按顺序执行?

时间:2010-04-24 23:56:38

标签: haskell io buffering

我遇到的问题是IO没有按顺序执行,即使在do构造中也是如此。

在下面的代码中,我只是跟踪剩下的卡片,卡片是一个字符元组(一个用于套装,一个用于值),然后用户不断被问到已经播放了哪些卡片。我希望putStr在每个输入之间执行,而不是像现在一样在最后执行。

module Main where
main = doLoop cards
doLoop xs = do  putStr $ show xs
                s <- getChar
                n <- getChar
                doLoop $ remove (s,n) xs
suits = "SCDH"
vals = "A23456789JQK"
cards = [(s,n) | s <- suits, n <- vals]
type Card = (Char,Char)
remove :: Card -> [Card] -> [Card]
remove card xs = filter (/= card) xs

3 个答案:

答案 0 :(得分:14)

如果问题出现在我认为的问题上,你的问题就是Haskell的IO被缓冲了:this question解释了发生了什么。当您运行已编译的Haskell程序时,GHC将输出存储在缓冲区中,并仅定期将其刷新到屏幕上;如果(a)缓冲区太满,(b)打印换行符,或(c)拨打hFlush stdout,则会这样做。

您可能会看到的另一个问题是getChar在读取换行符之前可能无法触发,但新行在您的输入流中;你也许可以通过额外的getChar解决这个问题来吞下换行符,但应该有更好的方法。

答案 1 :(得分:8)

absz的答案是正确的,Haskell的缓冲IO是导致你麻烦的原因。这是重写doLoop以获得您正在寻找的效果的一种方法:

doLoop xs = do  putStrLn $ show xs
                input <- getLine
                let s:n:_ = input
                doLoop $ remove (s,n) xs

这两个更改:使用putStrLn附加换行符并刷新输出(这可能是您想要的),并使用getLine一次获取一行(同样可能你想要的是什么。

答案 2 :(得分:6)

正如其他人所指出的那样,以putStr的形式缓冲是你的问题。

此外,样式点:putStrLn $ show xsprint xs

相同