具有惰性脊柱和严格叶子的数据结构示例

时间:2015-09-15 01:17:29

标签: haskell data-structures

提及here的一个表现技巧是:

  

作为一个安全的默认值:在脊椎中懒惰,在树叶中严格。

我无法想象这样的数据结构。

如果我以Lists为例,如果我在叶子中严格禁止,那么脊柱是否会自动严格?

是否有任何数据结构示例,其中脊椎是懒惰的,叶子是严格的?

2 个答案:

答案 0 :(得分:6)

“在脊椎中懒惰,在树叶中严格”是 API 的属性,而不是(仅)数据结构的属性。以下是它可能如何查找列表的示例:

module StrictList (StrictList, runStrictList, nil, cons, uncons, repeat) where

newtype StrictList a = StrictList { runStrictList :: [a] }

nil :: StrictList a
nil = StrictList []

cons :: a -> StrictList a -> StrictList a
cons x (StrictList xs) = x `seq` StrictList (x:xs)

uncons :: StrictList a -> Maybe (a, StrictList a)
uncons (StrictList []) = Nothing
uncons (StrictList (x:xs)) = Just (x, StrictList xs)

repeat :: a -> StrictList a
repeat x = x `seq` StrictList (let xs = x:xs in xs)

请注意,与内置列表相比,此API非常贫乏 - 这只是为了使插图保持较小,而不是出于根本原因。这里的关键点是你仍然可以支持像repeat这样的东西,其中脊椎必然是懒惰的(它是无限的!)但是在发生任何其他事情之前评估所有叶子。许多可以生成无限列表的其他列表操作可以适应叶子严格版本(尽管不是全部,如您所见)。

你还应该注意到,不一定可能采取叶子懒惰,脊椎懒惰的结构,并以自然的方式将其变成严格的,严格的,脊柱懒惰的结构;例如一个人不能写一个通用的fromList :: [a] -> StrictList a,以便:

  • fromList (repeat x) = repeat x
  • 所有有限长度runStrictList (fromList xs) = xs
  • xs

(原谅我的惩罚,我是repeat罪犯。

答案 1 :(得分:2)

这一点建议混合了两个相关但不同的想法。 Haskell程序员经常对这种区别不屑一顾,但这里很重要。

严格与非严格

这是语义上的区别。如果f,则函数f _|_ = _|_ strict ,否则为非严格函数。

渴望(按值调用)与懒惰(按需调用)

这是一个实施问题,可能会产生重大的性能影响。延迟评估是实现非严格语义的一种方法。

声明的真正含义

实际上,这意味着数据结构应该是 strict lazy 。数据结构的脊柱中的适量懒惰可能非常有用。有时它会提高性能的渐近性。它还可以提高缓存利用率并降低垃圾收集成本。另一方面,过多的懒惰(甚至在脊柱中,在某些情况下!)会导致延迟计算的有害累积。从API的角度来看,确保插入操作急切(因此严格)非常有用,这样您就可以知道存储在结构中的所有内容都已被强制。