什么是脊柱严格

时间:2014-03-07 12:02:08

标签: haskell data-structures lazy-evaluation strictness

在Haskell中,经常提到术语 spine strictness 与懒惰评估有关。虽然我对这意味着一个模糊的理解,但是对于具体的解释更好:

  • 数据结构的 spine 是什么
  • 脊椎严格性是什么意思?
  • 将脊柱严格数据结构与惰性数据结构进行比较时,的好处是什么?

1 个答案:

答案 0 :(得分:30)

这是一个例子

> length (undefined : 3 : 4 : undefined : [])
4
> length (2 : 3 : 4 : 5 : undefined)
<<loop>>

第一个列表包含底部元素,但列表的“形状”已完全定义。粗略地说,每个列表单元格都有一个明确定义的“指针”指向其下一个元素。这种“形状”称为脊柱。

相比之下,第二个列表已完全定义了元素,但未定义其主干。这是因为它不以空列表[]结尾,而是以非终止表达式undefined结束。在这种情况下,脊柱未定义。

函数length关心的是脊椎,而不是元素。所以它能够在第一种情况下工作(感谢懒惰),但不是第二种情况。我们说length在脊椎中是严格的,但不在列表的元素中。

类似地,在树数据结构中,书脊是树的“形状”。某些功能(如树高)可以在不检查元素的情况下编写,但只能编写脊柱。这种功能在脊柱上是严格的。

虽然某些功能必须是脊柱严格的(例如长度),但其他功能可以以脊柱严格或脊椎延迟的方式编写。例如,列表上的map是棘手的:它将在访问输入的所有主干之前返回输出的第一个元素。

可以获得更严格的变体
map' :: (a->b) -> [a] -> [b]
map' _ []     = []
map' f (x:xs) = (f x :) $! map' f xs

这是否有益取决于具体情况。考虑

-- apply n times function f
iter n f = foldr (.) id $ replicate n f

list1 = iter 1000 (map  succ) [1..10]
list2 = iter 1000 (map' succ) [1..10]

如果我要求head list1,我将强制仅在列表的第一个元素处应用1000个地图。这意味着在此之后将有1000个分配的内存在内存中占用空间。

相反,head list2将强制在整个列表中应用1000个地图。因此,所有1000个thunks都可以立即进行垃圾回收,回收内存。