是否有更严格的Data.Sequence?

时间:2013-02-08 09:44:16

标签: haskell data-structures sequence lazy-evaluation

以下示例显示了Data.Sequence的问题:

{-# LANGUAGE BangPatterns #-}
module Main where

import qualified Data.Sequence as S
import Data.Sequence ((|>), ViewL(..))
import Data.List (foldl')
import GHC.AssertNF

update !init !x = init |> x

main =
   do let !seq = foldl' update S.empty [1..10]
      assertNF seq

打印

Parameter not in normal form: 1 thunks found:
Deep (One (S# 1)) (_thunk (Deep (One ...) (_thunk ... ... ... ...) (Three ... ... ...) 93) (S# 95) (S# 96) (S# 97)) (Three (S# 98) (S# 99) (S# 100)) 100

但是,Data.Sequence的文档声称所有操作都是严格的,那么为什么插入后树没有完全评估?是否需要保证一些非常复杂的界限?

我们非常不喜欢这里的懒惰,所以我想知道是否有更严格的|>或类似的数据结构支持从后面追加到后面和枚举,可能是更有效的?

2 个答案:

答案 0 :(得分:13)

Data.Sequence是一个元素严格,数字严格的数据结构,带有一个懒惰的脊柱。

data FingerTree a
    = Empty
    | Single a
    | Deep {-# UNPACK #-} !Int !(Digit a) (FingerTree (Node a)) !(Digit a)

这意味着将对已插入的值进行求值评估,但仅在查询时评估结构的主干。 这通常是你想要的 - 较小的数据结构。

如果你想对它施加一个严格的脊椎,你将导致更高的插入成本,但你可能会获得其他地方。

尝试将fingertrees包修改为spine严格并查看它是否实际更快 - 我将有兴趣知道结果。


顺便说一句:“我们非常不喜欢这里的懒惰”,这不是避免脊椎懒惰数据结构的好理由。如果[a]是严格的脊椎,那将是一种可怕的数据类型。 Data.Sequence也是如此。您应该量化为什么spine-strictness对于您的用例是错误的语义。

答案 1 :(得分:11)

手指树的良好表现取决于懒惰。引用Hinze, Ralf; Paterson, Ross (2006), "Finger Trees: A Simple General-purpose Data Structure"

  

...   虽然结构使得懒惰的必要用途,但它也是合适的   对于提供惰性评估原语的严格语言。

并在分析其属性时:

  

......因此,在一系列操作中,平均成本是不变的。

     

如果使用挂起子树,则在持久设置中保持相同的边界   懒惰的评价。这可以确保脊柱深处的变换不会   发生,直到后续的操作需要下降到那么远。因为   以上属性的安全和危险的数字,到那个时候就足够了   廉价的浅层操作将被执行以支付这个昂贵的   评价。

因此,如果将实现从lazy更改为strict,您可能会失去良好的时间复杂性界限(取决于您使用的操作和顺序)。