执行顺序影响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中的每个表达式都是纯的,所以得到的结果是相同的。