2017-11-11 82 views
3

在Haskell中,我們試圖通過不改變變量或傳遞參數來以不可變的方式編寫大部分代碼,而是通過所需的更改從舊的創建新值。爲什麼不hSetBuffering返回一個新的句柄,而不是改變給定的句柄?

main = do 
withFile "something.txt" ReadMode (\handle -> do 
    hSetBuffering handle $ BlockBuffering (Just 2048) 
    contents <- hGetContents handle 
    putStr contents) 

那麼是什麼原因比hSetBuffering,這需要一個手柄,並將其緩衝模式的功能,改變了傳遞的handle本身,而不是用所需的緩衝模式返回一個新手柄?

+3

對於您只能讀取緩衝區,這可能是好的,但有兩個手柄,以具有獨立的緩衝器一樣可寫的對象聽起來像瘋狂的良方。 –

回答

6

對於常規的Haskell值,保留值的舊版本沒有問題。但是,Handle是對操作系統分配的可變資源的引用,以及進位狀態。在調用hSetBuffering版本後返回新的Handle版本後,之前版本的Handle版本仍然存在?他們應該反映這種變化嗎?如果答案是肯定的,那麼hSetBuffering的新句柄返回版本就有點謊言了。

如果類型系統以某種方式不允許在調用該函數後保留舊版本的Handle,那麼hSetBuffering的這個新的句柄返回版本可以工作。它可以通過強制執行一個約束來實現:接收Handle作爲參數的函數只能使用該參數單一時間,而像dup :: Handle -> (Handle,Handle)這樣的「複製」句柄的函數不允許使用

有一個(尚未被接受的)proposal擴展Haskell執行這些限制的能力。事實上,文件操作是其中一個激勵性的例子。從本文的第2.3節:

type File 
openFile :: FilePath → IOL 1 File 
readLine :: File ⊸ IOL 1 (File,Unrestricted ByteString) 
closeFile :: File ⊸ IOL ω() 

根據這項建議,我們只能有一個File的單一版本,在任何給定時間左右。 closeFile使得對File的引用不可用,因此我們無法關閉已經關閉的文件。每個讀取操作都採用先前版本的File,並隨讀取的數據一起返回一個新的操作。而hSetBuffering將有一個類型,如:

hSetBuffering :: BufferingMode -> File ⊸ IOL 1 File 
+0

感謝您的詳細解釋。 – sidoshi