关于hFlush和lazy evaluation的问题

Question about hFlush and lazy evaluation

我得到了同一个函数的三个定义:

prompt :: String -> IO String
prompt = (getLine <*) . (hFlush stdout <*) . putStrLn

prompt' :: String -> IO String
prompt' str = do
    putStrLn str
    hFlush stdout
    getLine

prompt'' :: String -> IO String
prompt'' str = putStrLn str >> hFlush stdout >> getLine

prompt'prompt'' 都在 运行 getLine 之前刷新标准输出,但不是 prompt。这是为什么?

因为那不是你要的。自

prompt = (getLine <*) . (hFlush stdout <*) . putStrLn

我们可以添加一个参数看看我们得到了什么:

prompt str = ((getLine <*) . (hFlush stdout <*) . putStrLn) str
           = getLine <* hFlush stdout <* putStrLn str

这要求 运行 按顺序执行 getLinehFlush stdoutputStrLn str 操作。 (那么该操作序列的结果值就是 getLine 一开始的任何结果值。)你想要这个:

prompt str = putStrLn str *> hFlush stdout *> getLine

或:

prompt = (*> getLine) . (*> hFlush stdout) . putStrLn

(其实大多数情况下默认的缓冲都是行缓冲或者更少,而你调用的是putStrLn,而不是putStr,所以none 这些解决方案实际上需要调用 hFlush stdout!)