When does `modify` copy the vector?

后端 未结 1 1479
攒了一身酷
攒了一身酷 2020-12-19 00:37

From https://hackage.haskell.org/package/vector-0.12.0.1/docs/Data-Vector.html#v:modify

Apply a destructive operation to a vector. The operation will

相关标签:
1条回答
  • 2020-12-19 01:12

    Modify calls Data.Vector.Generic.modify which calls clone which has the following rewrite rule:

    "clone/new [Vector]" forall p.
      clone (new p) = p
    

    So when something is in a syntactic form of new p it isn't copied. It appears modify, slice, init, tail, take, drop, unstream, and clone are the main thing that fuse well here. This is all closely related to the stream fusion work (google-able paper for deep dives) that underpins vector's design.

    EDIT: Based on your comment I'll elaborate. Only things syntactically in the form new p will avoid copying. Since you're probably not writing new yourself then it will only appear as a result of inlined use of function from the vector package. Looking at vector 1, it appears the functions I identified above use new and should thus allow modify to not copy if things are inlined and even then most those only preserve newness, the vector still had to be freshly constructed via something like create, force, modify, or unstream.

    For example, if you have the code:

    v = fromList [1..10]
    g = modify f v
    f = undefined
    

    Then v will be inlined and the vector is in the form new p (because fromList uses unstream which is new) and therefore modify will not have to copy the array.

    On the other hand, consider:

    v = let v0 = fromList [1..10] in 
    {-# NOINLINE v #-}
    g = modify f v
    

    Now v is not inlined explicitly - it could also not be inlined because it is from a different module or the expression is shared. As a result there is no code that is syntactically modify f (new p) and the rewrite rule won't fire.

    Less contrived, consider:

    g = let v = fromList [1..10]
            t = v ! 4
            v2 = modify f v
        in t + (v2 ! 4)
    

    This is a common pattern where a vector is both read and modified - it obviously can't be modified before the read and the rewrite rules either won't fire (because there is no new there) or you'll have to lose sharing of v.

    1 See here for the rules "slice/new [Vector]", for example.

    0 讨论(0)
提交回复
热议问题