我希望我的命令行 Haskell 程序能够像这样运行:程序等待用户输入,
- 用户输入一些东西,按“输入”
- Haskell 处理输入,在标准输出上显示结果
- Haskell 等待下一个用户输入
- 如果没有更多输入,用户通过 Ctrl+D 终止程序
我试过getContents。但是 getContents 在处理它们之前等待用户输入所有行。
我希望我的命令行 Haskell 程序能够像这样运行:程序等待用户输入,
我试过getContents。但是 getContents 在处理它们之前等待用户输入所有行。
这里有很多混乱。让我们试着把事情弄清楚。
我试过getContents。但是 getContents 在处理它们之前等待用户输入所有行。
这里最有可能的是你已经编译了你的程序,并且没有注意到输出的默认缓冲是块缓冲。这很容易解决:
f line = putStrLn ("Hi, " ++ line ++ "!")
main = do
hSetBuffering stdout LineBuffering -- or use NoBuffering
putStrLn "Enter some names."
input <- getContents
mapM_ f (lines input)
NoBuffering
如果您不打算在每行用户输入后打印整行(包括换行符),则应该使用。
要获得更准确的答案,我们需要查看您尝试过的无效代码。
问:但是在我的第一次尝试中,我使用:“interact show”,但它不起作用。你知道为什么吗?
答:因为 show 在其全部输入耗尽之前不会返回任何输出。
这个答案并不完全正确。真正的答案是show
生成一个没有换行符的字符串!(虽然如果输入的长度超过一行,字符序列有时['\\','\n']
会interact show
显示出来。)所以,对于,你真的必须使用NoBuffering
on stdout
。例如,如果你使用这个:
main = do
hSetBuffering stdout NoBuffering
interact show
...程序将在每一行之后打印更多输出。您可能还想将stdin
' 缓冲设置为NoBuffering
(而不是默认的LineBuffering
),因为show
它的效率足够高,它确实可以在每次击键后产生更多的输出。
您可以尝试使用该interact
功能。它接受一个类型的函数String -> String
并将其转换为读取 stdin 的操作,将其连续传递给函数,并将函数返回的字符串写入 stdout。如果您注意不要过度使用输入字符串,您将获得您请求的行为。
这避免了您使用interact
.
(如果我们不使用isEOF
,当我们按下 Ctrl+D 时会抛出异常。)
import Control.Monad (unless)
import System.IO (isEOF)
processEachLine :: (String -> IO a) -> IO ()
processEachLine k = do
finished <- isEOF
unless finished $ do
k =<< getLine
processEachLine k
在这里,我假设该k
函数本身打印所需的输出。很容易修改processEachLine
以打印输出,以便k
可以是纯的。