Reputation: 663
I have a simple program that just takes a string from the user and a key and encrypts the string with a caesar cipher function. The function itself works so I won't show to source for that. The issue is that when the compiler compiles the program it will allow me to input all the getLines and then after having inputted everything the program will print all the putStr and putStrLn then close. This ONLY happens when the program is executed using "runhaskell" or compiled and executed as an exe, ie. not in the interpreter. Here is the program:
main = do
choice <- prompt "Would you like to encrypt (1) or decrypt (2)? "
if choice == "1" then do
encrypt <- prompt "Enter code for encryption: "
k <- prompt "Enter key for the code: "
let key = read k in
putStrLn ("Encrypted message: " ++ (caesar key encrypt) ++ "\n")
else do
decrypt <- prompt "Enter code for decryption: "
k <- prompt "Enter key for the code: "
let key = read k in
putStrLn ("Decrypted message: " ++ (caesar (-key) decrypt) ++ "\n")
getLine
prompt str = do
putStr str
getLine
Output when run in the interpreter:
Prelude Main> main
Would you like to encrypt (1) or decrypt (2)? 1 <- the one is user input
Enter code for encryption: Hello world <- user input
Enter key for the code: 2 <- user input
Encrypted message: Jgnnq"yqtnf <- program output
Output when executed after compilation:
1 <- user has to input before the console is printed out
Hello world <--┘
2 <--┘
Would you like to encrypt (1) or decrypt (2)? Enter code for encryption: Enter key for the code: Encrypted message: Jgnnq"yqtnf
Is there something about putStrLn and putStr that I am overlooking? Do they only execute as the result of a function or something?
Also, the "prompt" function I created is not the issue because I replaced all the uses of prompt with their respective putStr's and getLine's and it still did the same thing.
Upvotes: 4
Views: 1064
Reputation: 153102
runhaskell
and ghci
are designed to start your program as quickly as possible, and de-emphasize the efficiency of running the program. For that reason they make many sub-optimal efficiency decisions compared to the ghc
, and one that's biting you here is that they use no buffering on standard input or output by default, while ghc
uses the more efficient line buffering by default. Since you never print a line ending during your prompt
s, in the compiled version, the buffer is not shown to the user... until you reach the putStrLn
at the end of the program that prints a line ending, and the whole buffer is shown at once.
You have some choices:
System.IO
and use hSetBuffering stdout NoBuffering
at the beginning of main
.System.IO
and use hFlush stdout
just before each call to getLine
.putStrLn
instead of putStr
everywhere.Upvotes: 9