[英]How are function parameters passed in Haskell?
我有一個內存使用率很高的容器數據類型,上面有一些正在處理的函數,這些函數都無法遍歷整個容器。 但是,如果要應用這些功能,則需要將這些未更改的數據塊從參數復制到結果中。 我的大多數函數看起來像這樣:
doStuff :: Container -> a -> Container
doStuff container x = Container {
field1 = field1 container,
field2 = myFunction $ field1 container,
...
}
我的問題是:是否通過將引用傳遞給field1來更新field1,或者將field1的內容復制到生成的Container的位置中?
重要的是要知道,因為我出於效率目的構建了整個數據類型,如果容器的內容由我的函數復制,該數據類型將消失。
以下所有評論均適用於GHC。
除非在特殊情況下(閱讀:程序員明確要求的地方),否則構造新的Container
將涉及field1
的單個指針副本。 field2
方程將創建一個thunk,引用計算myFunction $ field1 container
; 當該重擊被強制執行時,將通過向myFunction
傳遞一個指針(與以前相同!)來繼續。
為什么不使用記錄更新語法:
doStuff container = container { field2 = myFunction .... }
這將創建一個container
副本,其中只有一個字段field2
具有不同的值。 但是,兩個容器中所有其他字段中的值實際上將是兩個容器之間共享的相同值。
GHCi的證據:
> data Container = Container {field1::[Int], field2::[Int]} deriving Show
data Container = Container {field1 :: [Int], field2 :: [Int]}
field1 :: Container -> [Int]
field2 :: Container -> [Int]
> doStuff container = container { field2 = (++ [1]) $ field2 container }
doStuff :: Container -> Container
> xs=filter even [0..10::Int]
> :sprint xs
xs = _
> take 2 xs
[0,2]
> :sprint xs
xs = 0 : 2 : _
> doStuff (Container xs [0])
Container {field1 = [0,2,4,6,8,10], field2 = [0,1]}
> :sprint xs
xs = [0,2,4,6,8,10]
如我們所見, xs
被傳遞為“通過引用”。 沒有復制,即沒有創建新列表存儲來保存相同的值-像往常一樣僅使用指向列表的指針。
支持上述主張的另一個示例:
> c1 = Container (filter even [0..20::Int]) ([0])
c1 :: Container
> c2 = doStuff c1
c2 :: Container
> :sprint c1
c1 = <Ghci39.Container> _ [0]
> :sprint c2
c2 = _
> take 2 $ field1 c2
[0,2]
> :sprint c2
c2 = <Ghci39.Container> (0 : 2 : _) _
> :sprint c1
c1 = <Ghci39.Container> (0 : 2 : _) [0]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.