2012-04-17 66 views
4

处理用户输入无限,我想我的命令行的Haskell程序的功能是这样的: 程序等待用户输入,如何阅读和哈斯克尔

  1. 用户类型的东西,按“输入”
  2. 哈斯克尔处理输入,示出了在stdout
  3. Haskell中等待下一个用户输入
  4. 结果如果没有更多的输入,用户按Ctrl +终止程序d

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

+2

'getContents'返回* lazy *字符列表。也许消费功能太严格了。 – 2012-04-17 16:38:01

回答

7

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

我试过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产生一个没有换行的字符串! (虽然字符序列['\\','\n']确实有时显示,如果输入是超过一行长。)因此,对于interact show,您确实必须在stdout上使用NoBuffering。例如,如果你使用这个:

main = do 
    hSetBuffering stdout NoBuffering 
    interact show 

...程序将在每行之后输出更多的输出。您可能还想将stdin的缓冲设置为NoBuffering(而不是默认的LineBuffering),因为show具有足够的生产能力,因此每次击键后都能产生更多的输出。

5

使用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可以是纯粹的。

+0

如果你想要一个'String - > String'类型的函数,你可以很容易地创建一个类似的helper:'processLinesPure ::(String - > String) - > IO(); processLinesPure f = processEachLine(putStrLn。f)' – 2012-04-18 03:00:29

6

您可以尝试使用interact函数。它采用String -> String类型的函数,并将其转换为读取stdin的动作,将其连续传递给该函数,并将该函数返回的字符串写入stdout。如果你注意不要过度消费输入字符串,你会得到你所要求的行为。

+0

特别是'interact(unlines。map processTheInput。lines)'。 – dave4420 2012-04-17 16:38:00

+0

太棒了!但在我的第一次尝试中,我使用:“互动秀”,它不起作用。你知道为什么吗 ? – osager 2012-04-17 16:42:39

+1

@osager因为'show'在其整个输入已经耗尽之前不会返回任何输出; '互动'需要一个增量评估功能。 – 2012-04-17 16:45:57