I've got three definitions of the same function:
prompt :: String -> IO String
prompt = (getLine <*) . (hFlush stdout <*) . putStrLn
prompt' :: String -> IO String
prompt' str = do
putStrLn str
hFlush stdout
getLine
prompt'' :: String -> IO String
prompt'' str = putStrLn str >> hFlush stdout >> getLine
prompt'
and prompt''
both flush stdout before running getLine
, but not prompt
. Why is this?
Because that's not what you asked for. Since
prompt = (getLine <*) . (hFlush stdout <*) . putStrLn
we can just add an argument to see what we get:
prompt str = ((getLine <*) . (hFlush stdout <*) . putStrLn) str
= getLine <* hFlush stdout <* putStrLn str
This asks to run the actions getLine
, hFlush stdout
, and putStrLn str
, in that order. (Then the result value of that sequence of actions is whatever result value getLine
had at the very beginning.) You want this instead:
prompt str = putStrLn str *> hFlush stdout *> getLine
or:
prompt = (*> getLine) . (*> hFlush stdout) . putStrLn
(In fact, the default buffering in most cases is line buffering or less, and you are calling putStrLn
, not putStr
, so none of these solutions actually need a call to hFlush stdout
!)