5

我遇到了 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
4

3 回答 3

14

如果问题是我认为的问题,那么您的问题是 Haskell 的 IO 被缓冲:这个问题解释了正在发生的事情。当您运行已编译的 Haskell 程序时,GHC 将输出存储在缓冲区中,并且只会定期将其刷新到屏幕上;如果 (a) 缓冲区太满,(b) 如果打印换行符,或者 (c) 如果您调用hFlush stdout.

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

于 2010-04-25T00:06:59.933 回答
8

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

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

两个变化:用于putStrLn附加换行符并刷新输出(这可能是您想要的),并用于getLine一次获取一行输入(再次,可能是您想要的)。

于 2010-04-25T00:23:00.213 回答
6

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

另外,风格点:putStrLn $ show xsprint xs

于 2010-04-25T02:39:12.163 回答