执行顺序影响haskell的空间复杂度

执行顺序影响haskell的空间复杂度,haskell,Haskell,我在维基百科上读到哈斯克尔的故事: 在这篇文章中,有一个让我困惑的例子: 棘手的空间泄漏示例: (\xs -> head xs + last xs) [1..n] (\xs -> last xs + head xs) [1..n] 第一个版本在O(1)空间上运行。O(n)中的第二个 为什么 我假设last的实现方式如下: last [] = error "" last [r] = r last (_:t) = last t 所以尾部递归应该占用常量空间。为什么第二个表达式会产生

我在维基百科上读到哈斯克尔的故事:

在这篇文章中,有一个让我困惑的例子:

棘手的空间泄漏示例:

(\xs -> head xs + last xs) [1..n]
(\xs -> last xs + head xs) [1..n]
第一个版本在O(1)空间上运行。O(n)中的第二个

为什么

我假设
last
的实现方式如下:

last [] = error ""
last [r] = r
last (_:t) = last t

所以尾部递归应该占用常量空间。为什么第二个表达式会产生线性空间?

简单的答案是,在计算
a+b
时,表达式
a
在实际计算中会在
b
之前进行计算

通常
last xs
只占用O(1)个空间-当
last
向下遍历列表时,可以丢弃
xs
的元素。但是,如果另一个表达式需要
xs
,则另一个表达式的
xs
扩展必须保留在内存中,第二种情况就是这样,因为
head
似乎需要
xs


在第一种情况下,
head xs
被计算为“first”,它只计算
xs
的第一个元素。然后计算
last xs
,遍历列表。但是,由于不再需要列表中的元素,它们可能会在遍历过程中被丢弃。

作为某些规范的一部分,这在任何地方都能得到保证吗?或者它只是GHC中
+
如何工作的一个怪癖,它碰巧首先计算它的第一个参数,而不同的Haskell实现可以选择首先计算
+
的第二个参数,同时仍然符合规范?Haskell语言规范没有指定计算顺序。它甚至没有指定必须缓存结果,即在
fa+ga
中,实现可以决定对
a
进行两次评估。因为Haskell中的每个表达式都是纯的,所以得到的结果是相同的。