2010-02-18 99 views
8

我想在哈斯克爾的一個小實驗,想知道是否有可能利用懶惰來處理IO。我想編寫一個函數,它接受一個String(一個Chars列表),併產生一個字符串,懶洋洋地。然後,我希望能夠懶惰地從IO中緩慢地提供它的字符,因此每個字符都會在可用時立即進行處理,並且會在需要的字符可用時生成輸出。但是,我不太確定是否/如何從IO單元內的輸入中生成一個懶惰列表。Haskell中的「惰性IO」?

+0

請澄清:你需要一個接受一個字符串和「產生」一個字符串---「產生」=「返回」,「輸出到文件句柄」的函數,或者是什麼?然後你想「懶惰地從IO中提取字符」---這是什麼意思? – dave4420 2010-02-18 16:42:25

回答

14

Haskell中的常規字符串IO很懶。所以你的例子應該是開箱即用。

下面是一個例子,使用「交互」功能,它適用的功能字符的懶惰流:

interact :: (String -> String) -> IO() 

讓我們從輸入流中過濾出字母e,懶惰地(即,運行在不斷的空間):

main = interact $ filter (/= 'e') 

你也可以,如果你喜歡用getContents和putStr。他們都很懶。

運行它從字典中篩選字母「E」:

$ ghc -O2 --make A.hs 
$ ./A +RTS -s < /usr/share/dict/words 
... 
       2 MB total memory in use (0 MB lost due to fragmentation) 
... 

,所以我們看到它在一個恆定2M足跡跑了。

+2

你也可以在命令行看到這個效果。在shell/Terminal /運行Don的'A'程序,無論您的操作系統使用什麼,並直接輸入文本。假設它是行緩衝的,當你在每行之後按回車時,即使程序看起來只是對「過濾器」進行一次「調用」,你仍會立即看到過濾後的文本。 – Nefrubyr 2010-02-19 11:49:10

3
unsafeInterleaveIO :: IO a -> IO a 

unsafeInterleaveIO阿洛斯IO計算被推遲懶洋洋地。當通過IO a類型的值時,IO將僅在要求值a時執行。這用於實現惰性文件讀取,請參閱System.IO.hGetContents

例如,main = getContents >>= return . map Data.Char.toUpper >>= putStr是懶惰的;當你向標準輸入提供字符時,你會在標準輸出中獲得字符。

(這是一樣的書寫main = interact $ map Data.Char.toUpper,爲行蹤詭祕的回答。)

7

做懶IO的最簡單的方法涉及的功能,如interactreadFilehGetContents,而這樣,作爲穿上說;在書中Real World Haskell中有更多關於這些的討論,您可能會覺得有用。如果內存服務於我,所有這些功能最終都會使用ephemient提到的unsafeInterleaveIO來實現,所以您也可以按照自己的意願構建自己的函數。

另一方面,請注意unsafeInterleaveIO正如它在錫罐上所說的那樣:不安全的IO可能是明智的。使用它 - 或基於它的功能 - breaks purity and referential transparency。這允許顯然是純粹的功能(即,不返回IO動作)在評估時影響外部世界,從相同的參數產生不同的結果,以及所有其他不愉快的事情。在實踐中,使用unsafeInterleaveIO的最明智的方式不會造成問題,而簡單的錯誤通常會導致明顯且容易診斷的錯誤,但是您失去了一些很好的保證。

當然有其他選擇;你可以在Hackage上找到提供受限制的,safer lazy IOconceptually different approaches的各種圖書館。但是,鑑於問題在實際使用中很少出現,我認爲大多數人傾向於堅持內置的,技術上不安全的功能。