Haskell将putStr和putStrLn放在程序的末尾而不是在执行过程中

Bry*_*and 2 haskell ghc ghci

我有一个简单的程序,它仅从用户处获取一个字符串和一个密钥,并使用凯撒密码函数对字符串进行加密。该函数本身起作用,所以我不会显示源代码。问题是,当编译器编译程序时,它将允许我输入所有的getLines,然后在输入所有内容后,程序将打印所有的putStr和putStrLn,然后关闭。仅当使用“ runhaskell”执行程序或将其编译并执行为exe时才发生这种情况。不在口译员中。这是程序:

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
Run Code Online (Sandbox Code Playgroud)

在解释器中运行时的输出:

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
Run Code Online (Sandbox Code Playgroud)

编译后执行时的输出:

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
Run Code Online (Sandbox Code Playgroud)

我忽略了关于putStrLn和putStr的东西吗?它们是否仅是由于功能或其他原因而执行?

另外,我创建的“提示”功能也不是问题,因为我将所有使用提示的方式替换为它们各自的putStr和getLine,并且它仍然做同样的事情。

Dan*_*ner 7

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 prompts, 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:

  1. 明确要求没有缓冲。这将使编译后的程序稍微慢一些(在人机交互的速度下不太可能被注意到),但其行为更像解释版本。在的开头导入System.IO和使用。hSetBuffering stdout NoBufferingmain
  2. 当您知道要暂停以供用户输入时,显式刷新缓冲区。在每次调用之前导入System.IO和使用。hFlush stdoutgetLine
  3. 以两种缓冲模式之间行为相同的方式进行输出。使用putStrLn而不是putStr到处使用。