6

我希望我的命令行 Haskell 程序能够像这样运行:程序等待用户输入,

  1. 用户输入一些东西,按“输入”
  2. Haskell 处理输入,在标准输出上显示结果
  3. Haskell 等待下一个用户输入
  4. 如果没有更多输入,用户通过 Ctrl+D 终止程序

我试过getContents。但是 getContents 在处理它们之前等待用户输入所有行。

4

3 回答 3

9

这里有很多混乱。让我们试着把事情弄清楚。

我试过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显示出来。)所以,对于,你真的必须使用NoBufferingon stdout。例如,如果你使用这个:

main = do
    hSetBuffering stdout NoBuffering
    interact show

...程序将在每一行之后打印更多输出。您可能还想将stdin' 缓冲设置为NoBuffering(而不是默认的LineBuffering),因为show它的效率足够高,它确实可以在每次击键后产生更多的输出。

于 2012-04-17T17:53:26.237 回答
7

您可以尝试使用该interact功能。它接受一个类型的函数String -> String并将其转换为读取 stdin 的操作,将其连续传递给函数,并将函数返回的字符串写入 stdout。如果您注意不要过度使用输入字符串,您将获得您请求的行为。

于 2012-04-17T16:36:04.740 回答
6

使用isEOFgetLine读取输入。

这避免了您使用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可以是纯的。

于 2012-04-17T16:33:56.500 回答