Consider the example:
import qualified Data.Vector.Unboxed as Vector
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Unboxed.Mutable as MVector
process :: [Int] -> Vector Int -> Vector Int
process [] v = v
process (x:xs) v = process xs $ Vector.modify modify v
where
modify mv = do
old <- MVector.read mv x
MVector.write mv x (old + 1)
main :: IO ()
main = do
print $ process [1, 1, 3, 1] $ Vector.replicate 10 0
In core
on each iteration I see sequence of newByteArray#
, copyByteArray#
, readIntArray#
, writeIntArray#
and unsafeFreezeByteArray#
. It definitely creates intermediate copies.
Documentation states:
Apply a destructive operation to a vector. The operation will be performed in place if it is safe to do so and will modify a copy of the vector otherwise.
It is implemented as
modify p = new . New.modify p . clone
And there is RULE
"clone/new [Vector]" forall p.
clone (new p) = p
From my (pretty limited) understanding, two successive modify
should not create intermediate copies:
modify p2 . modify p1
=> new . New.modify p2 . clone . new . New.modify p1 . clone
=> new . New.modify p2 . New.modify p1 . clone
Why doesn't it work in the process
function? I think it should:
process [1, 2] v
=> process [2] $ Vector.modify modify v
=> process [] $ Vector.modify modify $ Vector.modify modify v
=> Vector.modify modify $ Vector.modify modify v
=> the same as above
How can I make it work?
I think it's the recursion that's stopping it.
There's nowhere in the source code that says modify
immediately followed by modify
. Each iteration of the function calls modify
again, but that happens at run-time, not compile-time. I think that's the problem. If you were to manually write three modify
calls in a line, they would fuse.
I can't think of a way to make this fuse automatically. You could of course manually call clone
and new
yourself, but I can't think of a way to get the compiler to do this for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With