2012-04-17 33 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