我想要更深入地理解Haskell中的懶惰。懶惰和I/O如何在Haskell中一起工作?
今天我想象下面的代碼片段:
data Image = Image { name :: String, pixels :: String }
image :: String -> IO Image
image path = Image path <$> readFile path
這裏吸引人的是,我可以簡單地創建一個Image實例,並通過它;如果我需要將讀取的圖像數據懶洋洋地 - 如果不是,讀取文件的時間和內存成本將被避免:
main = do
image <- image "file"
putStrLn $ length $ pixels image
不過是它如何工作?懶惰是如何與IO兼容的?無論我訪問pixels image
是否會調用readFile,或者如果我從未參考它,運行時是否會將該Thunk評估爲未評估?
如果圖像確實是懶懶地讀取的,那麼不可能發生I/O操作失常嗎?例如,如果在撥打image
後立即刪除該文件?現在putStrLn調用在嘗試讀取時什麼也找不到。
感謝您的回答! 事實上,RWH對hGetContents的描述使我對這個問題感到困惑。我沒有意識到這是一個特殊情況,並在下面使用了不安全的IO調用。所以基本上,我的示例在readFile操作被處理後立即讀取文件?如果是這樣,這似乎更加一致。 – Bill 2010-05-06 01:36:01
@Bill:這裏是readFile的實現,直接來自GHC的標準庫:'readFile name = openFile name ReadMode >> = hGetContents'所以不,你的例子屬於「作弊作弊者」類別。也就是說,懶惰的I/O功能對於大多數日常實際使用來說通常是足夠安全的,所以除非純度對您來說非常重要,否則不要過多地冒汗。 – 2010-05-06 01:50:27
我知道奧列格說'unsafeInterleaveIO'打破了參照透明度,但我不同意。我會說這只是非確定性的,就像'IO'單元中的許多事情一樣。 'getCurrentTime'是否中斷參照透明度,因爲我可以使用它來確定兩個本質上相等的函數中的哪一個更有效地實現? – 2010-05-07 05:30:28