9

I've got a series of network requests, that each take >10 seconds.
So that the user knows what's happening, I give updates:

main = do putStr "Downloading the first thing... "
          {- Net request -}
          putStrLn "DONE"
          putStr "Downloading the second thing... "
          {- Net request -}
          putStrLn "DONE"

With GHCi this works as expected, but compiled or with runghc, "Downloading" doesn't print till "DONE" does.

I've rewritten it with (>>=) and (>>), but I get the same problem.

What's going on?

Matvey Aksenov
  • 3,802
  • 3
  • 23
  • 45
amindfv
  • 8,438
  • 5
  • 36
  • 58

1 Answers1

16

The problem here isn't with the execution order. The statements execute in exactly the order you expect. The problem is that due to buffering, you don't actually see the results as soon as they happen.

Specifically terminal IO is line-buffered by default. This means that no output will appear on the screen until you print a newline or flush the buffer. So you need to either flush the´output stream using hFlush after executing putStr or you need to change stdout's buffering mode using hSetBuffering to not use line buffering.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • 10
    Just to mention there is nothing specific to `Haskell` in I/O buffering, it's same in `C`, `C++`, `Python`, etc. – Matvey Aksenov Dec 02 '11 at 19:52
  • 5
    @MatveyB.Aksenov: Well, the real issue here is that the buffering behavior differs when running a program from the REPL prompt vs. as a compiled binary. Also not specific to Haskell, but it is a chronic pitfall because of how people develop in Haskell. – C. A. McCann Dec 02 '11 at 20:07
  • 2
    Well most everything differs between the REPL and a compiled binary. From buffering to space use, optimizations and performance, and even (or, especially) type defaulting. – Thomas M. DuBuisson Dec 02 '11 at 20:15
  • 2
    @Thomas M. DuBuisson: But most of those are either really obvious or don't change the apparent behavior of the program, whereas the buffering thing tends to catch people by surprise. GHCi's type defaulting does create a lot of SO questions as well, though. – C. A. McCann Dec 02 '11 at 20:32
  • 2
    @Thomas M. DuBuisson: space use, optimizations, and performance are internals. I wouldn't expect to tune the performance of my code in GHCi, but I'd expect to be able to test its behavior. I agree that type-defaulting is a minefield, particularly since GHCi is used so extensively for checking types in code. – amindfv Dec 02 '11 at 20:47