我想將Haskell添加到我的工具箱中,所以我正在通過Real World Haskell進行工作。hGetContents如何實現記憶效率?
在輸入和輸出的一章,在the section on hGetContents
,我碰到這個例子就是:
import System.IO
import Data.Char(toUpper)
main :: IO()
main = do
inh <- openFile "input.txt" ReadMode
outh <- openFile "output.txt" WriteMode
inpStr <- hGetContents inh
let result = processData inpStr
hPutStr outh result
hClose inh
hClose outh
processData :: String -> String
processData = map toUpper
在此之後的代碼示例,作者繼續說:
注意
hGetContents
處理我們所有的閱讀。另外,請看processData
。這是一個純函數,因爲它沒有副作用,每次調用時都會返回相同的結果。它不需要知道,也沒有辦法告訴 - 在這種情況下,它的輸入是從文件中懶懶地讀取的。 它可以在磁盤上使用20個字符或500GB數據轉儲的情況下很好地工作。(NB重點是我的)
我的問題是:如何做hGetContents
或其結果值達到這個記憶效率,而不 - 在這個例子 - processData
「能說」,仍保留所有好處累積到純代碼(即processData
),特別是memoization?
<- hGetContents inh
返回字符串所以inpStr
勢必String
類型的值,這正是processData
接受的類型。但是,如果我正確理解Real World Haskell的作者,那麼這個字符串與其他字符串並不完全相同,因爲它沒有完全加載到內存中(或者完全評估,如果沒有完全評估的字符串存在..等等。 )在致電processData
之前。
因此,另一種方式來問我的問題是:如果inpStr
尚未完全在調用processData
的時間進行評估或加載到內存中,然後又怎能用來查找,如果到processData
一個memoized呼叫存在,不首先充分評估inpStr
?
是否存在類型String
的實例,每個實例的行爲都有所不同,但在這個抽象層次上不能區分開來?
非常感謝您的回答。 爲了滿足我的好奇心,你能告訴我GHC是否執行任何記憶,或者是否因爲剛纔提到的原因而沒有進行任何優化? 我猜想用原子參數記憶函數(即沒有數據結構,如列表)會更容易實現。 – Marcel
GHC根本不執行任何自動記憶功能。但它確實確保變量的值只計算一次。 – kqr
@MarcelOomens:通常很難回答,但是簡單枚舉上的分支(例如'data Foo = Foo | Bar | Baz')通常會變成memoized調用。這似乎是通常的GHC優化轉換的結果,我不認爲它有任何特別的支持。 –