Safe Haskell | None |
---|---|
Language | Haskell2010 |
Double-buffered storage
This module provides a safer alternative to the methods of the classes
Manifestable
and Manifestable2
:
store
instead ofmanifest
store2
instead ofmanifest2
setStore
instead ofmanifestStore
setStore2
instead ofmanifestStore2
Consider the following example:
bad = do arr <- newArr 20 vec1 <- manifest arr (1...20) vec2 <- manifest arr $ map (*10) $ reverse vec1 printf "%d\n" $ sum vec2
First the vector (1...20)
is stored into arr
. Then the result is used to
compute a new vector which is also stored into arr
. So the storage is
updated while it is being read from, leading to unexpected results.
Using this module, we can make a small change to the program:
good = do st <- newStore 20 vec1 <- store st (1...20) vec2 <- store st $ map (*10) $ reverse vec1 printf "%d\n" $ sum vec2
Now the program works as expected; i.e. gives the same result as the normal Haskell expression
sum $ map (*10) $ reverse [1..20]
The price we have to pay for safe storage is that
allocates
twice as much memory as newStore
l
. However, none of the other functions in
this module allocate any memory.newArr
l
Note that this module does not protect against improper use of
unsafeFreezeStore
. A vector from a frozen Store
is only valid as long as
the Store
is not updated.
Synopsis
- data Store a
- newStore :: (Syntax a, MonadComp m) => Data Length -> m (Store a)
- unsafeInplaceStore :: (Syntax a, MonadComp m) => Data Length -> m (Store a)
- unsafeFreezeStore :: (Syntax a, MonadComp m) => Data Length -> Store a -> m (Manifest a)
- unsafeFreezeStore2 :: (Syntax a, MonadComp m) => Data Length -> Data Length -> Store a -> m (Manifest2 a)
- setStore :: (Manifestable Run vec a, Finite vec, Syntax a) => Store a -> vec -> Run ()
- setStore2 :: (Manifestable2 Run vec a, Finite2 vec, Syntax a) => Store a -> vec -> Run ()
- store :: (Manifestable Run vec a, Finite vec, Syntax a) => Store a -> vec -> Run (Manifest a)
- store2 :: (Manifestable2 Run vec a, Finite2 vec, Syntax a) => Store a -> vec -> Run (Manifest2 a)
- loopStore :: (Integral i, PrimType i, Syntax a, Manifestable Run vec1 a, Finite vec1, Manifestable Run vec2 a, Finite vec2) => Store a -> IxRange (Data i) -> (Data i -> Manifest a -> Run vec1) -> vec2 -> Run (Manifest a)
- loopStore2 :: (Integral i, PrimType i, Syntax a, Manifestable2 Run vec1 a, Finite2 vec1, Manifestable2 Run vec2 a, Finite2 vec2) => Store a -> IxRange (Data i) -> (Data i -> Manifest2 a -> Run vec1) -> vec2 -> Run (Manifest2 a)
Documentation
newStore :: (Syntax a, MonadComp m) => Data Length -> m (Store a) Source #
Create a new double-buffered Store
This operation allocates two arrays of the given length.
unsafeInplaceStore :: (Syntax a, MonadComp m) => Data Length -> m (Store a) Source #
Create a new single-buffered Store
Using unsafeInplaceStore
instead of newStore
allows double-buffered
algorithms to run inplace.
store :: (Manifestable Run vec a, Finite vec, Syntax a) => Store a -> vec -> Run (Manifest a) Source #
store2 :: (Manifestable2 Run vec a, Finite2 vec, Syntax a) => Store a -> vec -> Run (Manifest2 a) Source #