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

McB*_*den 6 haskell

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

  1. 用户输入内容,按"输入"
  2. Haskell处理输入,在stdout上显示结果
  3. Haskell等待下一个用户输入
  4. 如果没有更多输入,用户通过Ctrl + D终止程序

我试过getContents.但getContents等待用户在处理之前键入所有行.

Dan*_*ner 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)
Run Code Online (Sandbox Code Playgroud)

NoBuffering如果您不打算在每行用户输入后打印整行(包括换行符),则应使用此选项.

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

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

这个答案不太正确.真正的答案是show产生一个没有换行符的字符串!(虽然字符序列['\\','\n'] 确实出现有时如果输入多行长.)所以,interact show你真的必须使用NoBufferingstdout.例如,如果您使用此:

main = do
    hSetBuffering stdout NoBuffering
    interact show
Run Code Online (Sandbox Code Playgroud)

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


dfl*_*str 7

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


dav*_*420 6

使用isEOFgetLine读取输入.

这可以避免您使用的懒惰i/o问题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
Run Code Online (Sandbox Code Playgroud)

这里我假设该k函数自己打印所需的输出.可以很容易地修改processEachLine输出以使其k纯净.