函数参数如何在Haskell中传递?

时间:2019-03-23 20:38:34

标签: haskell

我有一个内存使用率很高的容器数据类型,其中有一些函数在运行,而其中任何一个都不能遍历整个容器。但是,如果要应用这些功能,则需要将这些未更改的数据块从参数复制到结果中。我的大多数功能看起来像这样:

doStuff :: Container -> a -> Container 
doStuff container x = Container { 
    field1 = field1 container,
    field2 = myFunction $ field1 container,
    ...
    } 

我的问题是:是否通过将引用传递给field1来更新field1,还是将field1的内容复制到结果容器的位置?

要知道这很重要,因为我出于效率目的而构建了整个数据类型,如果容器的内容将被我的函数复制,则该数据类型将消失。

2 个答案:

答案 0 :(得分:3)

以下所有评论均适用于GHC。

除非在特殊情况下(阅读:程序员明确要求的地方),否则构造新的@Override protected void onStart() { super.onStart(); } 将涉及Container的单个指针副本。 field1方程将创建一个重击,引用计算field2;当该重击被强制执行时,它将通过向myFunction $ field1 container传递一个指针(与以前的指针相同!)来进行操作。

答案 1 :(得分:1)

为什么不使用记录更新语法:

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]