
David Sabel wrote:
The runtime system mostly has no concept of IO vs. non-IO evaluation. The IO monad is implemented as the following type:
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #)
which means that an IO action is simply a function from the world state to a pair of a new world state and a value. In other words, it's a straightfoward state monad, except that we use some optimised representations to eliminate some of the overhead of passing the state around.
Cheers, Simon
Ok so far, but when is the IO action performed?
Look at this small programm:
module Main(main) where
main = echoTwice
echo = getChar >>= putChar
echoTwice = echo >> echo
while executing: the program reads first two chararcters and then it writes the characters, but in my opinion it would be right to read one character, then write one characater, then read, then write. What's the reason for it?
Buffering.
If stdin/stdout correspond to a terminal, they are initially
line-buffered; otherwise, they are initially fully (block) buffered.
Also, if you're reading from a terminal, the terminal driver might
perform line buffering also (although, AFAICT, the run-time explicitly
turns it off).
You can change the buffering of stdin/stdout using IO.hSetBuffering.
The terminal buffering can be controlled using
PosixTTY.setTerminalAttributes.
BTW, this isn't a Haskell issue; you would see the same behaviour from
a program written in C.
--
Glynn Clements