当从 Haskell 函数返回列表模式时,引用了多少原始列表?

Ham*_*bly 2 haskell functional-programming

这是一个关于 Haskell 列表模式返回的问题。

如果我返回一个与函数输入之一匹配的基于 cons 的列表模式,该函数是否返回对原始列表头部的引用,或者是否返回一个新列表,其中新头部指向原始列表的尾部列表?

我的理解是,如果一个函数的输入中有 (x:xs) 模式,则 x 将引用头值,xs 将引用原始列表的尾部,因此如果我返回 xs 它将返回对尾部节点的引用,跳过复制尾部内容的需要。

但是,如果我返回整个模式或模式的一部分,会发生什么情况?编译器是否识别输入模式并利用原始列表中的节点返回引用,或者是否为基于 cons 的前导元素启动一个新列表并仅重用尾部?

foobar (x:xs) = xs
Run Code Online (Sandbox Code Playgroud)

foobar (x:xs) = (x:xs)
Run Code Online (Sandbox Code Playgroud)

foobar (x:y:zs) = (y:zs)
Run Code Online (Sandbox Code Playgroud)

lef*_*out 10

Haskell 语言没有定义这些。这是一个实施细节。该语言的级别足够高,无法直接观察到两种可能性之间的差异,除非使用了不同数量的内存。

一般来说,您应该期望创建一个新列表,并且仅重用尾部。但编译器通常可以优化它以重用整个东西。

如果您想确保重复使用原始引用,请改用 at 模式:

foobar l@(x:xs) = l
Run Code Online (Sandbox Code Playgroud)

如果你想确保创建一个新列表......好吧,我不知道是否有一种完全可靠的方法。但我也不明白为什么你首先会想要这个。

  • 这是正确的答案。如果我们想变得非常迂腐,编译器仍然可以将“foobar l@(x:xs) = l”“悲观”为“foobar l@(x:xs) = (x:xs)”,这将还是合法的。从某种意义上说,我们无法保证在一个方向上进行优化(编译器可能会分配或重用),并且无法保证在另一个方向上不会悲观化(编译器应该重用,但最终可能会选择分配)。尽管如此,当谈到性能(而不仅仅是语义)时,考虑这些假设的“敌对”实现在实践中并没有真正的用处。 (3认同)
  • 感谢您的答复。@ 模式似乎是针对我的担忧,即能够在返回时引用原始列表,同时仍然利用函数逻辑的模式。 (2认同)