HaskellElephant
HaskellElephant

Reputation: 9891

Why isn't my IO executed in order?

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

Upvotes: 6

Views: 975

Answers (3)

Don Stewart
Don Stewart

Reputation: 137947

Buffering, in the form of putStr, is your problem, as others have pointed out.

Also, a style point: putStrLn $ show xs is the same as print xs

Upvotes: 6

perimosocordiae
perimosocordiae

Reputation: 17797

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:

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

The two changes: use putStrLn to append a newline and flush the output (which is probably what you want), and use getLine to grab the input a line at a time (again, probably what you want).

Upvotes: 8

Antal Spector-Zabusky
Antal Spector-Zabusky

Reputation: 36622

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 extra getChar to swallow the newline, but there should probably be a better way.

Upvotes: 14

Related Questions