2013-06-08 29 views
5

Czy jest możliwe utrzymanie fuzji strumieniowej podczas przetwarzania funkcji vector, jeśli unsafeUpdate_ jest używana do aktualizacji niektórych elementów vector? Odpowiedź wydaje się być nie w teście, który zrobiłem. Dla poniżej kodu czasowego wektorów jest generowany w upd funkcji, co zostało potwierdzone w rdzeniu:Brak fuzji strumienia z unsafeUpdate_ w unboxed wektorze

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] 

w rdzeniu $wupd funkcja jest stosowana w sum - jak pokazano poniżej, wytwarza nowy 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` ... 

Istnieje niezła, ciasna pętla w rdzeniu dla funkcji sum, ale tuż przed tą pętlą, jest wywołanie funkcji $wupd, a więc tymczasowe generowanie.

Czy istnieje sposób na uniknięcie tymczasowego generowania w tym przykładzie? Sposób, w jaki o tym myślę, aktualizując wektor w indeksie i jest przypadkiem parsowania strumienia, ale działa tylko na strumień w indeksie i (pomijając resztę) i zastępując element tam innym elementem. Zatem aktualizacja wektora w dowolnej lokalizacji nie powinna przerwać fuzji strumieniowej, prawda?

+0

bok: 'yarr' popiera fuzję i rozwijając wraz ze zmianą w miejscu: http: //hackage.haskell .org/packages/archive/yarr/1.3.1/doc/html/Data-Yarr-Repr-Foreign.html # t: F – leventov

+0

@leventov, bardzo ładnie! Skoro wydajesz się być autorem tej biblioteki, czy byłbyś w stanie podzielić się tym, jak napisać funkcję topikowego uaktualniania w miejscu dla przykładu wektorowego powyżej? Z pewnością to, co zrobiłeś dla szubienicy, powinno mieć zastosowanie tutaj, nie? – Sal

+0

duża, duża wada 'yarr-1. *' Jest ściśle związana z IO. Edycja w miejscu to po prostu 'do {... write arr 0 2; ...} '. – leventov

Odpowiedz

5

Nie mogę być w 100% pewny, ponieważ z vector jest to żółw całkowicie w dół (nigdy nie docierasz do rzeczywistej implementacji, zawsze jest inny kierunek), ale o ile rozumiem, warianty update wymuszają nowy tymczasowy poprzez klonowanie:

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 

i modifyWithStream rozmowy clone (i 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) 

i nie widzę sposobu, w jaki vector by pozbyć z tego unsafeCopy ponownie.

+0

według tego [wektor recyklingu papieru] (http://www.cse.unsw.edu.au/~rl/publications/recycling.pdf), klon/nowy mają połączyć ze sobą, ale nie widzę go w moje eksperymenty. – Sal

1

Jeśli potrzebujesz zmienić jeden lub kilka elementów, istnieją ładne rozwiązania w bibliotekach repa i yarr. Zachowują fuzję (nie jestem pewien co do repa) i Haskella-idiomatycznego.

Repa, używając fromFunction:

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

Yarr, używając Delayed:

upd arr = Delayed (extent arr) (touchArray arr) (force arr) ix 
    where ix 0 = return 2 
     ix i = index arr i