【问题标题】:Is there a stricter Data.Sequence?有更严格的 Data.Sequence 吗?
【发布时间】:2013-02-08 09:44:16
【问题描述】:

以下示例显示了我们在使用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 的文档声称所有操作都是严格的,那么为什么插入后树没有完全评估?是否需要保证一些摊销的复杂性界限?

这里我们不太喜欢懒惰,所以不知道有没有更严格的|>或者类似的支持后面追加和前面枚举的数据结构,可能更高效?

【问题讨论】:

  • “我们不太喜欢这里的懒惰” ...您可能使用了错误的语言:)
  • @singpolyma:事实上,Haskell 非常适合我们 :)

标签: haskell data-structures sequence lazy-evaluation


【解决方案1】:

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

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

这意味着插入的值将被存储评估,但结构的脊椎将仅在查询时评估。 这通常是您想要的——更小的数据结构。

如果您想对其施加严格的脊椎,您将承担更高的插入成本,但您可能会在其他地方获得收益。

尝试将fingertrees包修改为spine strict,看看它是否真的更快——我很想知道结果。


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

【讨论】:

【解决方案2】:

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

... 结构虽然本质上利用了懒惰,但也很适合 适用于提供惰性求值原语的严格语言。

在分析其属性时:

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

如果子树使用 懒惰的评价。这确保了脊柱深处的转变不会 直到后续操作需要进行到那么远为止。因为 安全和危险数字的上述属性,到那时就足够了 将执行廉价的浅层操作来支付这种昂贵的费用 评估。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 1970-01-01
    • 2014-11-03
    相关资源
    最近更新 更多