5

vectorifunsafeUpdate_関数を使用して a の一部の要素を更新するときに、ストリームの融合を維持することは可能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]

コアでは、$wupdfunction が使用されsumます - 以下に示すように、それは new を生成します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 のストリームにのみ作用し (残りはスキップ)、そこの要素を別の要素に置き換える場合です。ですから、任意の場所でベクトルを更新しても、ストリームの融合は壊れませんよね?

4

2 に答える 2

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

于 2013-06-08T05:01:05.160 に答える
1

1 つまたはごく少数の要素を変更する必要がある場合は、ライブラリrepayarrライブラリに優れたソリューションがあります。それらは融合(私にはよくわかりませんrepa)とHaskellの慣用句を保持します。

レパ、使用fromFunction

upd arr = fromFunction (extent arr) ix
  where ix (Z .: 0) = 2
        ix i = index arr i

ヤール、使用Delayed

upd arr = Delayed (extent arr) (touchArray arr) (force arr) ix
  where ix 0 = return 2
        ix i = index arr i
于 2013-06-08T12:31:00.513 に答える