[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