简体   繁体   English

是否有更严格的Data.Sequence?

[英]Is there a stricter Data.Sequence?

The following example shows a problem that we have with Data.Sequence : 以下示例显示了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

It prints 它打印

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

However, the documentation of Data.Sequence claims that all the operations are strict, so why isn't the tree fully evaluated after the insert? 但是, Data.Sequence的文档声称所有操作都是严格的,那么为什么插入后树没有完全评估? Is it needed to guarantee some of the amoritized complexity bounds? 是否需要保证一些非常复杂的界限?

We don't like laziness here very much, so I wonder if there is a stricter |> or a similar data structure that supports appending to the back and enumeration from the front, possibly a more efficient one? 我们在这里不太喜欢懒惰,所以我想知道是否有一个更严格的|>或类似的数据结构支持从后面追加到后面和枚举,可能是一个更有效的?

Data.Sequence is a element strict, digit strict data structure with a lazy spine. Data.Sequence是一个元素严格,数字严格的数据结构,具有惰性脊柱。

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

This means inserted values will be stored evaluated, but the spine of the structure will only be evaluated on query. 这意味着将对已插入的值进行求值评估,但仅在查询时评估结构的主干。 That's often what you want -- smaller data structures. 这通常是你想要的 - 较小的数据结构。

If you want to force a strict spine on it, you will incur a heavier insertion cost, but you might gain somewhere else. 如果你想对它施加一个严格的脊椎,你将会产生更大的插入成本,但你可能会获得其他地方。

Try modifying the fingertrees package to be spine strict and see if it is actually faster -- I will be interested to know the result. 尝试将fingertrees包修改为spine严格并查看它是否实际更快 - 我将有兴趣知道结果。


As an aside: "We don't like laziness here very much," isn't a good reason to avoid spine-lazy data structures. 顺便说一句:“我们不太喜欢这里的懒惰”,这不是避免脊椎懒惰数据结构的好理由。 If [a] was spine strict, it would be a terrible data type. 如果[a]是严格的脊椎,那将是一种可怕的数据类型。 The same may be true for Data.Sequence. Data.Sequence也是如此。 You should quantify why spine-strictness is the wrong semantics for your use case. 您应该量化为什么spine-strictness是您的用例的错误语义。

Good performance of finger trees depends on laziness. 手指树的良好表现取决于懒惰。 To quote from Hinze, Ralf; 引用Hinze,Ralf; Paterson, Ross (2006), "Finger Trees: A Simple General-purpose Data Structure" : Paterson,Ross(2006),“手指树:简单的通用数据结构”

... Although the structure makes essential use of laziness, it is also suitable for strict languages that provide a lazy evaluation primitive. ...虽然结构基本上使用了懒惰,但它也适用于提供惰性评估原语的严格语言。

and when analyzing its properties: 并在分析其属性时:

...Consequently, in a sequence of operations, the average cost is constant. ......因此,在一系列操作中,平均成本是不变的。

The same bounds hold in a persistent setting if subtrees are suspended using lazy evaluation. 如果使用延迟评估暂停子树,则相同的边界在持久设置中保持。 This ensures that transformations deep in the spine do not take place until a subsequent operation needs to go down that far. 这确保了在后续操作需要向下移动那么之前不会发生脊柱深处的变换。 Because of the above properties of safe and dangerous digits, by that time enough cheap shallow operations will have been performed to pay for this expensive evaluation. 由于上述安全和危险数字的特性,到那个时候,已经进行了足够便宜的浅层操作来支付这种昂贵的评估费用。

So if you change the implementation from lazy to strict, you could possibly lose the good time complexity bounds (depending on what operations you use and in what order). 因此,如果将实现从lazy更改为strict,则可能会失去良好的时间复杂性界限(取决于您使用的操作和顺序)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM