如果使用vector
函数来更新unsafeUpdate_
的某些元素,是否可以在处理vector
时保持流融合?答案在我做的测试中似乎没有。对于下面的代码,临时向量在upd
函数中生成,如核心中所确认的那样:
module Main where
import Data.Vector.Unboxed as U
upd :: Vector Int -> Vector Int
upd v = U.unsafeUpdate_ v (U.fromList [0]) (U.fromList [2])
sum :: Vector Int -> Int
sum = U.sum . upd
main = print $ Main.sum $ U.fromList [1..3]
在核心中,$wupd
中使用sum
函数 - 如下所示,它会生成新的bytearray
:
$wupd :: Vector Int -> Vector Int
$wupd =
\ (w :: Vector Int) ->
case w `cast` ... of _ { Vector ipv ipv1 ipv2 ->
case main11 `cast` ... of _ { Vector ipv3 ipv4 ipv5 ->
case main7 `cast` ... of _ { Vector ipv6 ipv7 ipv8 ->
runSTRep
(\ (@ s) (s :: State# s) ->
case >=# ipv1 0 of _ {
False -> case main6 ipv1 of wild { };
True ->
case newByteArray# (*# ipv1 8) (s `cast` ...)
of _ { (# ipv9, ipv10 #) ->
case (copyByteArray# ipv2 (*# ipv 8) ipv10 0 (*# ipv1 8) ipv9)
`cast` ...
sum
函数的核心有一个很好的紧密循环,但就在该循环之前,有一个$wupd
函数的调用,因此是一个临时代。
这里的例子有没有办法避免临时生成?我考虑它的方式,更新索引i中的向量是解析流但仅作用于索引i中的流(跳过其余的),并用另一个元素替换该元素的情况。因此,更新任意位置的矢量不应该破坏流融合,对吧?
答案 0 :(得分:5)
我无法100%确定,因为vector
它的海龟一直在下降(你从未真正达到实际的实施,总是有另一个间接),但据我了解,update
变体迫使新的临时克隆:
unsafeUpdate_ :: (Vector v a, Vector v Int) => v a -> v Int -> v a -> v a
{-# INLINE unsafeUpdate_ #-}
unsafeUpdate_ v is w
= unsafeUpdate_stream v (Stream.zipWith (,) (stream is) (stream w))
unsafeUpdate_stream :: Vector v a => v a -> Stream (Int,a) -> v a
{-# INLINE unsafeUpdate_stream #-}
unsafeUpdate_stream = modifyWithStream M.unsafeUpdate
和modifyWithStream
来电clone
(和new
),
modifyWithStream :: Vector v a
=> (forall s. Mutable v s a -> Stream b -> ST s ())
-> v a -> Stream b -> v a
{-# INLINE modifyWithStream #-}
modifyWithStream p v s = new (New.modifyWithStream p (clone v) s)
new :: Vector v a => New v a -> v a
{-# INLINE_STREAM new #-}
new m = m `seq` runST (unsafeFreeze =<< New.run m)
-- | Convert a vector to an initialiser which, when run, produces a copy of
-- the vector.
clone :: Vector v a => v a -> New v a
{-# INLINE_STREAM clone #-}
clone v = v `seq` New.create (
do
mv <- M.new (length v)
unsafeCopy mv v
return mv)
我认为vector
无法再次摆脱unsafeCopy
。
答案 1 :(得分:1)
如果您需要更改一个或几个元素,repa
和yarr
库中有很好的解决方案。他们保留融合(我不确定repa
)和Haskell-idiomatic。
使用fromFunction
进行修复:
upd arr = fromFunction (extent arr) ix
where ix (Z .: 0) = 2
ix i = index arr i
Yarr,使用Delayed
:
upd arr = Delayed (extent arr) (touchArray arr) (force arr) ix
where ix 0 = return 2
ix i = index arr i