为什么我的IO没有按顺序执行?
我遇到了 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
I got a problem with IO not executing in order, even inside a do construct.
In the following code I am just keeping track of what cards are left, where the card is a tuple of chars (one for suit and one for value) then the user is continously asked for which cards have been played. I want the putStr
to be executed between each input, and not at the very end like it is now.
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果问题是我认为的那样,那么你的问题是 Haskell 的 IO 被缓冲: 这个问题解释了发生了什么。当您运行已编译的 Haskell 程序时,GHC 将输出存储在缓冲区中,并且仅定期将其刷新到屏幕上;如果 (a) 缓冲区太满,(b) 如果打印换行符,或者 (c) 如果您调用
hFlush stdout
,它就会这样做。您可能会看到的另一个问题是,在读取换行符之前,
getChar
可能不会触发,但随后换行符位于您的输入流中;您也许可以使用额外的 getChar 来吞掉换行符来解决此问题,但可能应该有更好的方法。If the problem is what I think it is, your problem is that Haskell's IO is buffered: this question explains what's happening. When you run a compiled Haskell program, GHC stores output in the buffer and only periodically flushes it to the screen; it does so if (a) the buffer is too full, (b) if a newline is printed, or (c) if you call
hFlush stdout
.The other problem you may be seeing is that
getChar
may not fire until a newline is read, but then the newline is in your input stream; you could perhaps solve this with an extragetChar
to swallow the newline, but there should probably be a better way.absz 的答案是正确的,Haskell 的缓冲 IO 才是给你带来麻烦的原因。这是重写
doLoop
以获得您想要的效果的一种方法:两个更改:使用
putStrLn
附加换行符并刷新输出(这可能是你想要的),并使用getLine
一次抓取一行输入(同样,可能是你想要的)。absz's answer is correct, Haskell's buffered IO is what's causing you trouble. Here's one way to rewrite your
doLoop
to have the effect you're looking for:The two changes: use
putStrLn
to append a newline and flush the output (which is probably what you want), and usegetLine
to grab the input a line at a time (again, probably what you want).正如其他人指出的那样,以 putStr 形式进行缓冲是您的问题。
另外,样式点:
putStrLn $ show xs
与print xs
相同Buffering, in the form of putStr, is your problem, as others have pointed out.
Also, a style point:
putStrLn $ show xs
is the same asprint xs