如何在Haskell中无限地读取和处理用户输入

时间:2012-04-17 16:28:06

标签: haskell

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

  1. 用户输入内容,按“输入”
  2. Haskell处理输入,在stdout上显示结果
  3. Haskell等待下一个用户输入
  4. 如果没有更多输入,用户通过Ctrl + D终止程序
  5. 我试过getContents。但getContents等待用户在处理之前键入所有行。

3 个答案:

答案 0 :(得分:8)

这里有很多混乱。让我们试着清理一下。

  

我试过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

要获得更准确的答案,我们需要查看您尝试过的无效代码。

  问:但是在我的第一次尝试中,我使用:“互动节目”,它不起作用。你知道为什么吗?   答:因为show在整个输入用尽之前不会返回任何输出。

这个答案不太正确。真正的答案是show生成一个没有换行符的字符串! (虽然字符序列['\\','\n'] 有时会显示输入多于一行。)因此,对于interact show,您必须使用NoBufferingstdout。例如,如果您使用此:

main = do
    hSetBuffering stdout NoBuffering
    interact show

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

答案 1 :(得分:7)

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

答案 2 :(得分:6)

使用isEOFgetLine来阅读输入。

这可以避免使用interact时出现的懒惰i / o问题。

(如果我们不使用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可以是纯粹的。