我有一个应用程序,其中使用Vector作为代码的一部分是有效的。但是,在计算过程中我需要跟踪一些元素。我听说你可以从Data.Vectors获得O(n)摊销连接(通过通常的数组增长技巧),但我认为我做得不对。所以我们假设我们有以下设置:
import Data.Vector((++),Vector)
import Prelude hiding ((++))
import Control.Monad.State.Strict
data App = S (Vector Int)
add :: Vector Int -> State App ()
add v1 = modify (\S v2 -> S (v2 ++ v1))
在这种情况下,add
是否以摊销的O(n)时间运行?如果没有,我如何让add
这样做(我需要在状态中存储(forall s. MVector s Int)
吗?)。是否有更有效的方式来实施add
?
答案 0 :(得分:2)
我也不太了解矢量库,所以我必须坚持一般原则。对它进行基准测试,运行一系列类似于您在应用程序中所期望的添加,并查看您获得的性能。如果它“足够好”,很棒,坚持使用简单的代码。如果没有,在将(forall s. MVector s Int)
存储在状态(你不能直接,元组不能保存forall类型,所以你需要包装它)之前,尝试通过转换为改进添加行为可变的向量并在冻结之前执行连接以再次获得不可变向量,大致
add v1 = do
S v2 <- get
let v3 = runST $ do
m1 <- unsafeThaw v2
m2 <- unsafeGrow m1 (length v1)
-- copy contents of v1 behind contents of v2
unsafeFreeze m2
put (S v3)
您可能需要在那里插入一些严格性。但是,如果unsafeGrow需要复制,则不能保证摊销的O(n)行为。
您可以通过
获得摊销的O(n)行为