[Haskell-beginners] Help with getLine and getChar

Daniel Fischer daniel.is.fischer at googlemail.com
Fri Oct 28 01:45:20 CEST 2011


On Friday 28 October 2011, 01:20:48, Avery Robinson wrote:
> I'm writing a program that calculates the maximum height of a stomp
> rocket (or any free falling object) given the starting height of the
> object and the amount of time that it takes to hit the ground. Here's
> what I have written: http://pastebin.com/KBJdPEJd
> 
> The behavior that I am expecting is something like this:
> 
> Starting height (ft): [user enters something here]
> Total air time (seconds): [user enters something here]
> Maximum height (ft): [the program's answer]
> Another? (Y/N)
> 
> Then everything starts over if the user presses y, and execution stops
> if the user presses n.
> 
> What actually happens:
> 1. The program waits for user input for both of the two fields before
> anything else, then it prints the prompts along with the answer.
> 2. The user needs to press enter before the their response to "Another?
> (Y/N)" is reacted to. I'd rather that the response is instant after just
> the y or n key is pressed.
> 
> I don't really understand exactly how lazy evaluation works in the
> context of IO, so any help will be much appreciated.

That's not a problem with lazy evaluation and IO, it's a simple buffering 
issue.
While in ghci stdin and stdout are normally unbuffered, for compiled 
programmes, they are usually line-buffered, so nothing will actually be 
printed to the terminal until a newline enters the output buffer or the 
output buffer is full.
To get the prompts output before the user enters the inputs, you need to

import System.IO

and then you have the choice whether you want to
a) turn off buffering completely (for the programme), that means performing

hSetBuffering stdout NoBuffering

at the beginning of main
b) manually flush the output buffer for the prompts, that means

     do ...
        putStr "Starting height (ft): "
        hFlush stdout
        rawStartingHeight <- getLine
        ...

etc.

For small programmes like this, turning off buffering is simpler, but in 
programmes that produce a lot of output, it adds relevant overhead to 
output, so then manually flushing at the desired places is preferable.

For the input, the situation is similar, you can globally turn off input 
buffering via 'hSetBuffering stdin NoBuffering' or do it locally in yOrN.

However, the above may not work on Windows (buffering control used to be 
broken on Windows, I don't know the current state).



More information about the Beginners mailing list