ghc --make Vs runhaskell

Hi !, I have the following program from “Learn You a Haskell” ( http://learnyouahaskell.com/input-and-output#randomness ). When i run this using runhaskell, code works perfectly fine. However, when i compile and run the binary file, code behaves differently. Basically, in the following code, we print a line first and the read the line from stdin. This behavior works perfectly fine when using “runhaskell guess.hs”. But when i say “./guess”, i had to type in a number directly ( i.e. first prompt is skipped ). btw.. i am using mac yosomite command terminal. Any help greatly appreciated.. Thanks a lot in advance.. import System.Random import Control.Monad(when) main = do ranGen <- getStdGen let (rand,_) = randomR (1,10) ranGen :: (Int,StdGen) putStr "Guess a number between 1 and 10 : " numStr <- getLine when(not $ null numStr) $ do let num = read numStr if rand == num then putStrLn "Yuhaa!! you are right baby!" else putStrLn $ "Sorry dude!! it was " ++ show rand newStdGen main

On 4 February 2015 at 05:23, Madhu Babu
Basically, in the following code, we print a line first and the read the line from stdin. This behavior works perfectly fine when using “runhaskell guess.hs”. But when i say “./guess”, i had to type in a number directly ( i.e. first prompt is skipped ).
This is most likely due to stdio buffering; usually stdin/stdout are line buffered, so data you write with putStr may not actually be written until a newline is written. This post / thread details some ways to handle this problem: https://www.haskell.org/pipermail/beginners/2010-March/003692.html -- mithrandi, i Ainil en-Balandor, a faer Ambar

Thanks a lot. .this really helps..
On Feb 3, 2015 10:35 PM, "Tristan Seligmann"
On 4 February 2015 at 05:23, Madhu Babu
wrote: Basically, in the following code, we print a line first and the read the line from stdin. This behavior works perfectly fine when using “runhaskell guess.hs”. But when i say “./guess”, i had to type in a number directly ( i.e. first prompt is skipped ).
This is most likely due to stdio buffering; usually stdin/stdout are line buffered, so data you write with putStr may not actually be written until a newline is written. This post / thread details some ways to handle this problem:
https://www.haskell.org/pipermail/beginners/2010-March/003692.html -- mithrandi, i Ainil en-Balandor, a faer Ambar

On Tue, Feb 3, 2015 at 10:23 PM, Madhu Babu
Basically, in the following code, we print a line first and the read the line from stdin. This behavior works perfectly fine when using “runhaskell guess.hs”. But when i say “./guess”, i had to type in a number directly ( i.e. first prompt is skipped ).
runhaskell is presumably using unbuffered I/O for some reason, so outputting directly to the terminal. The compiled program follows standard Unix buffering conventions: line buffering on output to a terminal, so the putStr is sitting in a buffer waiting to see a newline output. C / C++ programs also do buffering, but there's a heinous hack which detects reads on stdin and flushes stdout beforehand. (Heinous because there is no guarantee that they are actually related --- but naïve programmers invariably do not learn about line buffering and expect all output to be unbuffered(*), and C standard library programmers eventually gave up and catered to them after years of trying to get them to pay attention. I have a nasty suspicion we're going to end up with a similar horrible hack in Haskell eventually.) You can use hFlush from System.IO to flush the prompt out to the terminal, or disable output buffering with hSetBuffering in the same module. (*) At some point someone will pop up and say that on modern computers, buffering is obsolete because it's fast enough that horribly inefficient character-at-a-time I/O is good enough. Yet, I can *still* see visible hesitations when character-at-a-time I/O is used on a modern Intel core i5/i7. And your disk benchmarks will *tank* even with server-class disk subsystems. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

I just want to pop up and say that on modern computers...
Seriously though, wouldn't it be reasonable if putStr flushed? Often in
Haskell one constructs a long string to be output and there could still be
buffering.
On Feb 4, 2015 4:36 AM, "Brandon Allbery"
On Tue, Feb 3, 2015 at 10:23 PM, Madhu Babu
wrote: Basically, in the following code, we print a line first and the read the line from stdin. This behavior works perfectly fine when using “runhaskell guess.hs”. But when i say “./guess”, i had to type in a number directly ( i.e. first prompt is skipped ).
runhaskell is presumably using unbuffered I/O for some reason, so outputting directly to the terminal. The compiled program follows standard Unix buffering conventions: line buffering on output to a terminal, so the putStr is sitting in a buffer waiting to see a newline output.
C / C++ programs also do buffering, but there's a heinous hack which detects reads on stdin and flushes stdout beforehand. (Heinous because there is no guarantee that they are actually related --- but naïve programmers invariably do not learn about line buffering and expect all output to be unbuffered(*), and C standard library programmers eventually gave up and catered to them after years of trying to get them to pay attention. I have a nasty suspicion we're going to end up with a similar horrible hack in Haskell eventually.)
You can use hFlush from System.IO to flush the prompt out to the terminal, or disable output buffering with hSetBuffering in the same module.
(*) At some point someone will pop up and say that on modern computers, buffering is obsolete because it's fast enough that horribly inefficient character-at-a-time I/O is good enough. Yet, I can *still* see visible hesitations when character-at-a-time I/O is used on a modern Intel core i5/i7. And your disk benchmarks will *tank* even with server-class disk subsystems.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On 4/02/2015, at 4:35 pm, Brandon Allbery
C / C++ programs also do buffering, but there's a heinous hack which detects reads on stdin and flushes stdout beforehand. (Heinous because there is no guarantee that they are actually related --- but naïve programmers invariably do not learn about line buffering and expect all output to be unbuffered(*), and C standard library programmers eventually gave up and catered to them after years of trying to get them to pay attention. I have a nasty suspicion we're going to end up with a similar horrible hack in Haskell eventually.)
Looking in the last public draft of C99, section 7.19.3 has this: When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered.
Furthermore, characters are intended to be transmitted as a block to the host environment when a buffer is filled, when input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment.
So the "heinous hack" is not about stdin or stdout specifically; the standard requirement is that getting input from ANY line-buffered stream forces EVERY line-buffered output stream to be flushed. And it's this way precisely *because* the C runtime doesn't know whether two such streams are "related" or not, so it plays safe. Given things like sockets, STREAMS, and ptys, I am not sure that it is _possible_ for a Unix system to determine whether two streams are or are not "related" reliably. Solaris and OpenBSD do what the standard requires. A local copy of the Linux manual pages says (in setbuf(3)): When an output stream ... is line buffered characters are saved up until a newline is output or input is read from any stream attached to a terminal device (typically stdin). I hope that's wrong. There's other GNU documentation that disagrees, saying that every output stream is flushed whenever any input stream "actually reads data from its file" and not mentioning line buffering at all. I suspect that Linux is doing the right thing, but digging through the glibc-2.20 sources left me even more confused than the Linux documenters.

On Wed, Feb 4, 2015 at 10:10 PM, Richard A. O'Keefe
Given things like sockets, STREAMS, and ptys, I am not sure that it is _possible_ for a Unix system to determine whether two streams are or are not "related" reliably.
It's not. I was not implying that it was, or that it was even a good idea to try to do so. On the other hand, flushing *every* line-buffered FILE is rather overkill but less heinous than highly dubious and untestable assumptions about relationships. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

Hey Madhu,
Right, this is another gotcha -- haskell has a bunch of them.
As Tristan and Brandon have remarked, the runhaskell interpreter and
compiled programs handle output buffering differently.
Here are changes to make your game work:
On Wed, Feb 4, 2015 at 10:23 AM, Madhu Babu
import System.Random import Control.Monad(when)
import System.IO
main = do ranGen <- getStdGen let (rand,_) = randomR (1,10) ranGen :: (Int,StdGen)
hSetBuffering stdout NoBuffering
putStr "Guess a number between 1 and 10 : "
You might want to take a look at the "Summing Two Numbers" section here: https://www.haskell.org/onlinereport/io.html -- Kim-Ee
participants (6)
-
Brandon Allbery
-
Johan Holmquist
-
Kim-Ee Yeoh
-
Madhu Babu
-
Richard A. O'Keefe
-
Tristan Seligmann