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

时间:2019-07-11 16:51:27

标签: 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

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

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

编译后执行时的输出:

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

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

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

1 个答案:

答案 0 :(得分:7)

runhaskellghci旨在尽可能快地启动您的程序,而不再强调运行程序的效率。因此,与ghc相比,它们做出了许多次优效率决策,而在此困扰您的是,它们默认情况下不对标准输入或输出使用任何缓冲,而ghc使用更高效的决策。默认情况下,行缓冲。由于您从未打印过prompt结束的行,因此在编译版本中,缓冲区不会显示给用户...直到打印程序结束时到达putStrLn为止。行结尾,整个缓冲区立即显示。

您有一些选择:

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