diff --git a/Data/Vector.hs b/Data/Vector.hs
--- a/Data/Vector.hs
+++ b/Data/Vector.hs
@@ -1,8 +1,8 @@
-{-# LANGUAGE MagicHash, UnboxedTuples, FlexibleInstances, MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
 
 -- |
 -- Module      : Data.Vector
--- Copyright   : (c) Roman Leshchinskiy 2008
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -13,7 +13,7 @@
 --
 
 module Data.Vector (
-  Vector,
+  Vector, MVector,
 
   -- * Length information
   length, null,
@@ -53,6 +53,8 @@
 
   -- * Scans
   prescanl, prescanl',
+  postscanl, postscanl',
+  scanl, scanl', scanl1, scanl1',
 
   -- * Enumeration
   enumFromTo, enumFromThenTo,
@@ -61,16 +63,12 @@
   toList, fromList
 ) where
 
-import           Data.Vector.IVector ( IVector(..) )
-import qualified Data.Vector.IVector    as IV
-import qualified Data.Vector.Mutable.ST as Mut
+import qualified Data.Vector.Generic as G
+import           Data.Vector.Mutable  ( MVector(..) )
+import           Data.Primitive.Array
 
 import Control.Monad.ST ( runST )
 
-import GHC.ST   ( ST(..) )
-import GHC.Prim ( Array#, unsafeFreezeArray#, indexArray#, (+#) )
-import GHC.Base ( Int(..) )
-
 import Prelude hiding ( length, null,
                         replicate, (++),
                         head, last,
@@ -81,52 +79,52 @@
                         elem, notElem,
                         foldl, foldl1, foldr, foldr1,
                         and, or, sum, product, minimum, maximum,
+                        scanl, scanl1,
                         enumFromTo, enumFromThenTo )
 
 import qualified Prelude
 
 data Vector a = Vector {-# UNPACK #-} !Int
                        {-# UNPACK #-} !Int
-                                      (Array# a)
+                       {-# UNPACK #-} !(Array a)
 
 instance Show a => Show (Vector a) where
     show = (Prelude.++ " :: Data.Vector.Vector") . ("fromList " Prelude.++) . show . toList
 
-instance IVector Vector a where
+instance G.Vector Vector a where
   {-# INLINE vnew #-}
   vnew init = runST (do
-                       Mut.Vector i n marr# <- init
-                       ST (\s# -> case unsafeFreezeArray# marr# s# of
-                               (# s2#, arr# #) -> (# s2#, Vector i n arr# #)))
+                       MVector i n marr <- init
+                       arr <- unsafeFreezeArray marr
+                       return (Vector i n arr))
 
   {-# INLINE vlength #-}
   vlength (Vector _ n _) = n
 
   {-# INLINE unsafeSlice #-}
-  unsafeSlice (Vector i _ arr#) j n = Vector (i+j) n arr#
+  unsafeSlice (Vector i _ arr) j n = Vector (i+j) n arr
 
   {-# INLINE unsafeIndexM #-}
-  unsafeIndexM (Vector (I# i#) _ arr#) (I# j#)
-    = case indexArray# arr# (i# +# j#) of (# x #) -> return x
+  unsafeIndexM (Vector i _ arr) j = indexArrayM arr (i+j)
 
 instance Eq a => Eq (Vector a) where
   {-# INLINE (==) #-}
-  (==) = IV.eq
+  (==) = G.eq
 
 instance Ord a => Ord (Vector a) where
   {-# INLINE compare #-}
-  compare = IV.cmp
+  compare = G.cmp
 
 -- Length
 -- ------
 
 length :: Vector a -> Int
 {-# INLINE length #-}
-length = IV.length
+length = G.length
 
 null :: Vector a -> Bool
 {-# INLINE null #-}
-null = IV.null
+null = G.null
 
 -- Construction
 -- ------------
@@ -134,38 +132,38 @@
 -- | Empty vector
 empty :: Vector a
 {-# INLINE empty #-}
-empty = IV.empty
+empty = G.empty
 
 -- | Vector with exaclty one element
 singleton :: a -> Vector a
 {-# INLINE singleton #-}
-singleton = IV.singleton
+singleton = G.singleton
 
 -- | Vector of the given length with the given value in each position
 replicate :: Int -> a -> Vector a
 {-# INLINE replicate #-}
-replicate = IV.replicate
+replicate = G.replicate
 
 -- | Prepend an element
 cons :: a -> Vector a -> Vector a
 {-# INLINE cons #-}
-cons = IV.cons
+cons = G.cons
 
 -- | Append an element
 snoc :: Vector a -> a -> Vector a
 {-# INLINE snoc #-}
-snoc = IV.snoc
+snoc = G.snoc
 
 infixr 5 ++
 -- | Concatenate two vectors
 (++) :: Vector a -> Vector a -> Vector a
 {-# INLINE (++) #-}
-(++) = (IV.++)
+(++) = (G.++)
 
 -- | Create a copy of a vector. Useful when dealing with slices.
 copy :: Vector a -> Vector a
 {-# INLINE copy #-}
-copy = IV.copy
+copy = G.copy
 
 -- Accessing individual elements
 -- -----------------------------
@@ -173,31 +171,31 @@
 -- | Indexing
 (!) :: Vector a -> Int -> a
 {-# INLINE (!) #-}
-(!) = (IV.!)
+(!) = (G.!)
 
 -- | First element
 head :: Vector a -> a
 {-# INLINE head #-}
-head = IV.head
+head = G.head
 
 -- | Last element
 last :: Vector a -> a
 {-# INLINE last #-}
-last = IV.last
+last = G.last
 
 -- | Monadic indexing which can be strict in the vector while remaining lazy in
 -- the element
 indexM :: Monad m => Vector a -> Int -> m a
 {-# INLINE indexM #-}
-indexM = IV.indexM
+indexM = G.indexM
 
 headM :: Monad m => Vector a -> m a
 {-# INLINE headM #-}
-headM = IV.headM
+headM = G.headM
 
 lastM :: Monad m => Vector a -> m a
 {-# INLINE lastM #-}
-lastM = IV.lastM
+lastM = G.lastM
 
 -- Subarrays
 -- ---------
@@ -208,50 +206,50 @@
                   -> Int   -- ^ length
                   -> Vector a
 {-# INLINE slice #-}
-slice = IV.slice
+slice = G.slice
 
 -- | Yield all but the last element without copying.
 init :: Vector a -> Vector a
 {-# INLINE init #-}
-init = IV.init
+init = G.init
 
 -- | All but the first element (without copying).
 tail :: Vector a -> Vector a
 {-# INLINE tail #-}
-tail = IV.tail
+tail = G.tail
 
 -- | Yield the first @n@ elements without copying.
 take :: Int -> Vector a -> Vector a
 {-# INLINE take #-}
-take = IV.take
+take = G.take
 
 -- | Yield all but the first @n@ elements without copying.
 drop :: Int -> Vector a -> Vector a
 {-# INLINE drop #-}
-drop = IV.drop
+drop = G.drop
 
 -- Permutations
 -- ------------
 
 accum :: (a -> b -> a) -> Vector a -> [(Int,b)] -> Vector a
 {-# INLINE accum #-}
-accum = IV.accum
+accum = G.accum
 
 (//) :: Vector a -> [(Int, a)] -> Vector a
 {-# INLINE (//) #-}
-(//) = (IV.//)
+(//) = (G.//)
 
 update :: Vector a -> Vector (Int, a) -> Vector a
 {-# INLINE update #-}
-update = IV.update
+update = G.update
 
 backpermute :: Vector a -> Vector Int -> Vector a
 {-# INLINE backpermute #-}
-backpermute = IV.backpermute
+backpermute = G.backpermute
 
 reverse :: Vector a -> Vector a
 {-# INLINE reverse #-}
-reverse = IV.reverse
+reverse = G.reverse
 
 -- Mapping
 -- -------
@@ -259,11 +257,11 @@
 -- | Map a function over a vector
 map :: (a -> b) -> Vector a -> Vector b
 {-# INLINE map #-}
-map = IV.map
+map = G.map
 
 concatMap :: (a -> Vector b) -> Vector a -> Vector b
 {-# INLINE concatMap #-}
-concatMap = IV.concatMap
+concatMap = G.concatMap
 
 -- Zipping/unzipping
 -- -----------------
@@ -271,28 +269,28 @@
 -- | Zip two vectors with the given function.
 zipWith :: (a -> b -> c) -> Vector a -> Vector b -> Vector c
 {-# INLINE zipWith #-}
-zipWith = IV.zipWith
+zipWith = G.zipWith
 
 -- | Zip three vectors with the given function.
 zipWith3 :: (a -> b -> c -> d) -> Vector a -> Vector b -> Vector c -> Vector d
 {-# INLINE zipWith3 #-}
-zipWith3 = IV.zipWith3
+zipWith3 = G.zipWith3
 
 zip :: Vector a -> Vector b -> Vector (a, b)
 {-# INLINE zip #-}
-zip = IV.zip
+zip = G.zip
 
 zip3 :: Vector a -> Vector b -> Vector c -> Vector (a, b, c)
 {-# INLINE zip3 #-}
-zip3 = IV.zip3
+zip3 = G.zip3
 
 unzip :: Vector (a, b) -> (Vector a, Vector b)
 {-# INLINE unzip #-}
-unzip = IV.unzip
+unzip = G.unzip
 
 unzip3 :: Vector (a, b, c) -> (Vector a, Vector b, Vector c)
 {-# INLINE unzip3 #-}
-unzip3 = IV.unzip3
+unzip3 = G.unzip3
 
 -- Filtering
 -- ---------
@@ -300,17 +298,17 @@
 -- | Drop elements which do not satisfy the predicate
 filter :: (a -> Bool) -> Vector a -> Vector a
 {-# INLINE filter #-}
-filter = IV.filter
+filter = G.filter
 
 -- | Yield the longest prefix of elements satisfying the predicate.
 takeWhile :: (a -> Bool) -> Vector a -> Vector a
 {-# INLINE takeWhile #-}
-takeWhile = IV.takeWhile
+takeWhile = G.takeWhile
 
 -- | Drop the longest prefix of elements that satisfy the predicate.
 dropWhile :: (a -> Bool) -> Vector a -> Vector a
 {-# INLINE dropWhile #-}
-dropWhile = IV.dropWhile
+dropWhile = G.dropWhile
 
 -- Searching
 -- ---------
@@ -319,25 +317,25 @@
 -- | Check whether the vector contains an element
 elem :: Eq a => a -> Vector a -> Bool
 {-# INLINE elem #-}
-elem = IV.elem
+elem = G.elem
 
 infix 4 `notElem`
 -- | Inverse of `elem`
 notElem :: Eq a => a -> Vector a -> Bool
 {-# INLINE notElem #-}
-notElem = IV.notElem
+notElem = G.notElem
 
 -- | Yield 'Just' the first element matching the predicate or 'Nothing' if no
 -- such element exists.
 find :: (a -> Bool) -> Vector a -> Maybe a
 {-# INLINE find #-}
-find = IV.find
+find = G.find
 
 -- | Yield 'Just' the index of the first element matching the predicate or
 -- 'Nothing' if no such element exists.
 findIndex :: (a -> Bool) -> Vector a -> Maybe Int
 {-# INLINE findIndex #-}
-findIndex = IV.findIndex
+findIndex = G.findIndex
 
 -- Folding
 -- -------
@@ -345,66 +343,66 @@
 -- | Left fold
 foldl :: (a -> b -> a) -> a -> Vector b -> a
 {-# INLINE foldl #-}
-foldl = IV.foldl
+foldl = G.foldl
 
 -- | Lefgt fold on non-empty vectors
 foldl1 :: (a -> a -> a) -> Vector a -> a
 {-# INLINE foldl1 #-}
-foldl1 = IV.foldl1
+foldl1 = G.foldl1
 
 -- | Left fold with strict accumulator
 foldl' :: (a -> b -> a) -> a -> Vector b -> a
 {-# INLINE foldl' #-}
-foldl' = IV.foldl'
+foldl' = G.foldl'
 
 -- | Left fold on non-empty vectors with strict accumulator
 foldl1' :: (a -> a -> a) -> Vector a -> a
 {-# INLINE foldl1' #-}
-foldl1' = IV.foldl1'
+foldl1' = G.foldl1'
 
 -- | Right fold
 foldr :: (a -> b -> b) -> b -> Vector a -> b
 {-# INLINE foldr #-}
-foldr = IV.foldr
+foldr = G.foldr
 
 -- | Right fold on non-empty vectors
 foldr1 :: (a -> a -> a) -> Vector a -> a
 {-# INLINE foldr1 #-}
-foldr1 = IV.foldr1
+foldr1 = G.foldr1
 
 -- Specialised folds
 -- -----------------
 
 and :: Vector Bool -> Bool
 {-# INLINE and #-}
-and = IV.and
+and = G.and
 
 or :: Vector Bool -> Bool
 {-# INLINE or #-}
-or = IV.or
+or = G.or
 
 sum :: Num a => Vector a -> a
 {-# INLINE sum #-}
-sum = IV.sum
+sum = G.sum
 
 product :: Num a => Vector a -> a
 {-# INLINE product #-}
-product = IV.product
+product = G.product
 
 maximum :: Ord a => Vector a -> a
 {-# INLINE maximum #-}
-maximum = IV.maximum
+maximum = G.maximum
 
 minimum :: Ord a => Vector a -> a
 {-# INLINE minimum #-}
-minimum = IV.minimum
+minimum = G.minimum
 
 -- Unfolding
 -- ---------
 
 unfoldr :: (b -> Maybe (a, b)) -> b -> Vector a
 {-# INLINE unfoldr #-}
-unfoldr = IV.unfoldr
+unfoldr = G.unfoldr
 
 -- Scans
 -- -----
@@ -412,23 +410,53 @@
 -- | Prefix scan
 prescanl :: (a -> b -> a) -> a -> Vector b -> Vector a
 {-# INLINE prescanl #-}
-prescanl = IV.prescanl
+prescanl = G.prescanl
 
 -- | Prefix scan with strict accumulator
 prescanl' :: (a -> b -> a) -> a -> Vector b -> Vector a
 {-# INLINE prescanl' #-}
-prescanl' = IV.prescanl'
+prescanl' = G.prescanl'
 
+-- | Suffix scan
+postscanl :: (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE postscanl #-}
+postscanl = G.postscanl
+
+-- | Suffix scan with strict accumulator
+postscanl' :: (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE postscanl' #-}
+postscanl' = G.postscanl'
+
+-- | Haskell-style scan
+scanl :: (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE scanl #-}
+scanl = G.scanl
+
+-- | Haskell-style scan with strict accumulator
+scanl' :: (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE scanl' #-}
+scanl' = G.scanl'
+
+-- | Scan over a non-empty 'Vector'
+scanl1 :: (a -> a -> a) -> Vector a -> Vector a
+{-# INLINE scanl1 #-}
+scanl1 = G.scanl1
+
+-- | Scan over a non-empty 'Vector' with a strict accumulator
+scanl1' :: (a -> a -> a) -> Vector a -> Vector a
+{-# INLINE scanl1' #-}
+scanl1' = G.scanl1'
+
 -- Enumeration
 -- -----------
 
 enumFromTo :: Enum a => a -> a -> Vector a
 {-# INLINE enumFromTo #-}
-enumFromTo = IV.enumFromTo
+enumFromTo = G.enumFromTo
 
 enumFromThenTo :: Enum a => a -> a -> a -> Vector a
 {-# INLINE enumFromThenTo #-}
-enumFromThenTo = IV.enumFromThenTo
+enumFromThenTo = G.enumFromThenTo
 
 -- Conversion to/from lists
 -- ------------------------
@@ -436,10 +464,10 @@
 -- | Convert a vector to a list
 toList :: Vector a -> [a]
 {-# INLINE toList #-}
-toList = IV.toList
+toList = G.toList
 
 -- | Convert a list to a vector
 fromList :: [a] -> Vector a
 {-# INLINE fromList #-}
-fromList = IV.fromList
+fromList = G.fromList
 
diff --git a/Data/Vector/Fusion/Stream.hs b/Data/Vector/Fusion/Stream.hs
--- a/Data/Vector/Fusion/Stream.hs
+++ b/Data/Vector/Fusion/Stream.hs
@@ -1,8 +1,8 @@
-{-# LANGUAGE ExistentialQuantification, FlexibleInstances #-}
+{-# LANGUAGE ExistentialQuantification, FlexibleInstances, Rank2Types #-}
 
 -- |
 -- Module      : Data.Vector.Fusion.Stream
--- Copyright   : (c) Roman Leshchinskiy 2008
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -18,6 +18,9 @@
   -- * Types
   Step(..), Stream, MStream,
 
+  -- * In-place markers
+  inplace, inplace',
+
   -- * Size hints
   size, sized,
 
@@ -56,12 +59,15 @@
 
   -- * Scans
   prescanl, prescanl',
+  postscanl, postscanl',
+  scanl, scanl',
+  scanl1, scanl1',
 
   -- * Conversions
   toList, fromList, liftStream,
 
   -- * Monadic combinators
-  mapM_, foldM
+  mapM_, foldM, fold1M, foldM', fold1M'
 ) where
 
 import Data.Vector.Fusion.Stream.Size
@@ -79,6 +85,7 @@
                         elem, notElem,
                         foldl, foldl1, foldr, foldr1,
                         and, or,
+                        scanl, scanl1,
                         mapM_ )
 
 -- | The type of pure streams 
@@ -87,6 +94,42 @@
 -- | Alternative name for monadic streams
 type MStream = M.Stream
 
+inplace :: (forall m. Monad m => M.Stream m a -> M.Stream m a)
+        -> Stream a -> Stream a
+{-# INLINE_STREAM inplace #-}
+inplace f s = f s
+
+{-# RULES
+
+"inplace/inplace [Vector]"
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a)
+         (g :: forall m. Monad m => MStream m a -> MStream m a)
+         s.
+  inplace f (inplace g s) = inplace (f . g) s
+
+  #-}
+
+inplace' :: (forall m. Monad m => M.Stream m a -> M.Stream m b)
+         -> Stream a -> Stream b
+{-# INLINE_STREAM inplace' #-}
+inplace' f s = f s
+
+-- FIXME: We'd like to have this
+{- RULES
+
+"inplace' [Vector]" inplace' = inplace
+-}
+-- but it's only available in 6.13
+-- (see http://hackage.haskell.org/trac/ghc/ticket/3670)
+
+{-# RULES
+
+"inplace' [Vector]"
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a).
+  inplace' f = inplace f
+
+  #-}
+
 -- | Convert a pure stream to a monadic stream
 liftStream :: Monad m => Stream a -> M.Stream m a
 {-# INLINE_STREAM liftStream #-}
@@ -130,7 +173,7 @@
 
 -- | Replicate a value to a given length
 replicate :: Int -> a -> Stream a
-{-# INLINE_STREAM replicate #-}
+{-# INLINE replicate #-}
 replicate = M.replicate
 
 -- | Prepend an element
@@ -332,6 +375,37 @@
 {-# INLINE prescanl' #-}
 prescanl' = M.prescanl'
 
+-- | Suffix scan
+postscanl :: (a -> b -> a) -> a -> Stream b -> Stream a
+{-# INLINE postscanl #-}
+postscanl = M.postscanl
+
+-- | Suffix scan with strict accumulator
+postscanl' :: (a -> b -> a) -> a -> Stream b -> Stream a
+{-# INLINE postscanl' #-}
+postscanl' = M.postscanl'
+
+-- | Haskell-style scan
+scanl :: (a -> b -> a) -> a -> Stream b -> Stream a
+{-# INLINE scanl #-}
+scanl = M.scanl
+
+-- | Haskell-style scan with strict accumulator
+scanl' :: (a -> b -> a) -> a -> Stream b -> Stream a
+{-# INLINE scanl' #-}
+scanl' = M.scanl'
+
+-- | Scan over a non-empty 'Stream'
+scanl1 :: (a -> a -> a) -> Stream a -> Stream a
+{-# INLINE scanl1 #-}
+scanl1 = M.scanl1
+
+-- | Scan over a non-empty 'Stream' with a strict accumulator
+scanl1' :: (a -> a -> a) -> Stream a -> Stream a
+{-# INLINE scanl1' #-}
+scanl1' = M.scanl1'
+
+
 -- Comparisons
 -- -----------
 
@@ -381,13 +455,29 @@
 
 -- | Apply a monadic action to each element of the stream
 mapM_ :: Monad m => (a -> m ()) -> Stream a -> m ()
-{-# INLINE_STREAM mapM_ #-}
+{-# INLINE mapM_ #-}
 mapM_ f = M.mapM_ f . liftStream
 
 -- | Monadic fold
 foldM :: Monad m => (a -> b -> m a) -> a -> Stream b -> m a
-{-# INLINE_STREAM foldM #-}
+{-# INLINE foldM #-}
 foldM m z = M.foldM m z . liftStream
+
+-- | Monadic fold over non-empty stream
+fold1M :: Monad m => (a -> a -> m a) -> Stream a -> m a
+{-# INLINE fold1M #-}
+fold1M m = M.fold1M m . liftStream
+
+-- | Monadic fold with strict accumulator
+foldM' :: Monad m => (a -> b -> m a) -> a -> Stream b -> m a
+{-# INLINE foldM' #-}
+foldM' m z = M.foldM' m z . liftStream
+
+-- | Monad fold over non-empty stream with strict accumulator
+fold1M' :: Monad m => (a -> a -> m a) -> Stream a -> m a
+{-# INLINE fold1M' #-}
+fold1M' m = M.fold1M' m . liftStream
+
 
 -- Conversions
 -- -----------
diff --git a/Data/Vector/Fusion/Stream/Monadic.hs b/Data/Vector/Fusion/Stream/Monadic.hs
--- a/Data/Vector/Fusion/Stream/Monadic.hs
+++ b/Data/Vector/Fusion/Stream/Monadic.hs
@@ -2,7 +2,7 @@
 
 -- |
 -- Module      : Data.Vector.Fusion.Stream.Monadic
--- Copyright   : (c) Roman Leshchinskiy 2008
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -45,8 +45,8 @@
   elem, notElem, find, findM, findIndex, findIndexM,
 
   -- * Folding
-  foldl, foldlM, foldM, foldl1, foldl1M,
-  foldl', foldlM', foldl1', foldl1M',
+  foldl, foldlM, foldl1, foldl1M, foldM, fold1M,
+  foldl', foldlM', foldl1', foldl1M', foldM', fold1M',
   foldr, foldrM, foldr1, foldr1M,
 
   -- * Specialised folds
@@ -57,6 +57,9 @@
 
   -- * Scans
   prescanl, prescanlM, prescanl', prescanlM',
+  postscanl, postscanlM, postscanl', postscanlM',
+  scanl, scanlM, scanl', scanlM',
+  scanl1, scanl1M, scanl1', scanl1M',
 
   -- * Conversions
   toList, fromList
@@ -74,7 +77,8 @@
                         filter, takeWhile, dropWhile,
                         elem, notElem,
                         foldl, foldl1, foldr, foldr1,
-                        and, or )
+                        and, or,
+                        scanl, scanl1 )
 import qualified Prelude
 
 -- | Result of taking a single step in a stream
@@ -122,7 +126,7 @@
 {-# INLINE_STREAM singleton #-}
 singleton x = Stream (return . step) True (Exact 1)
   where
-    {-# INLINE step #-}
+    {-# INLINE_INNER step #-}
     step True  = Yield x False
     step False = Done
 
@@ -131,7 +135,7 @@
 {-# INLINE_STREAM replicate #-}
 replicate n x = Stream (return . step) n (Exact (max n 0))
   where
-    {-# INLINE step #-}
+    {-# INLINE_INNER step #-}
     step i | i > 0     = Yield x (i-1)
            | otherwise = Done
 
@@ -151,6 +155,7 @@
 {-# INLINE_STREAM (++) #-}
 Stream stepa sa na ++ Stream stepb sb nb = Stream step (Left sa) (na + nb)
   where
+    {-# INLINE_INNER step #-}
     step (Left  sa) = do
                         r <- stepa sa
                         case r of
@@ -228,7 +233,7 @@
 {-# INLINE_STREAM init #-}
 init (Stream step s sz) = Stream step' (Nothing, s) (sz - 1)
   where
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' (Nothing, s) = liftM (\r ->
                            case r of
                              Yield x s' -> Skip (Just x,  s')
@@ -248,7 +253,7 @@
 {-# INLINE_STREAM tail #-}
 tail (Stream step s sz) = Stream step' (Left s) (sz - 1)
   where
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' (Left  s) = liftM (\r ->
                         case r of
                           Yield x s' -> Skip (Right s')
@@ -268,7 +273,7 @@
 {-# INLINE_STREAM take #-}
 take n (Stream step s sz) = Stream step' (s, 0) (smaller (Exact n) sz)
   where
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' (s, i) | i < n = liftM (\r ->
                              case r of
                                Yield x s' -> Yield x (s', i+1)
@@ -282,7 +287,7 @@
 {-# INLINE_STREAM drop #-}
 drop n (Stream step s sz) = Stream step' (s, Just n) (sz - Exact n)
   where
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' (s, Just i) | i > 0 = liftM (\r ->
                                 case r of
                                    Yield x s' -> Skip (s', Just (i-1))
@@ -316,7 +321,7 @@
 {-# INLINE_STREAM mapM #-}
 mapM f (Stream step s n) = Stream step' s n
   where
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' s = do
                 r <- step s
                 case r of
@@ -356,7 +361,7 @@
 zipWithM f (Stream stepa sa na) (Stream stepb sb nb)
   = Stream step (sa, sb, Nothing) (smaller na nb)
   where
-    {-# INLINE step #-}
+    {-# INLINE_INNER step #-}
     step (sa, sb, Nothing) = liftM (\r ->
                                case r of
                                  Yield x sa' -> Skip (sa', sb, Just x)
@@ -385,7 +390,7 @@
 zipWith3M f (Stream stepa sa na) (Stream stepb sb nb) (Stream stepc sc nc)
   = Stream step (sa, sb, sc, Nothing) (smaller na (smaller nb nc))
   where
-    {-# INLINE step #-}
+    {-# INLINE_INNER step #-}
     step (sa, sb, sc, Nothing) = do
         r <- stepa sa
         return $ case r of
@@ -420,7 +425,7 @@
 {-# INLINE_STREAM filterM #-}
 filterM f (Stream step s n) = Stream step' s (toMax n)
   where
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' s = do
                 r <- step s
                 case r of
@@ -441,7 +446,7 @@
 {-# INLINE_STREAM takeWhileM #-}
 takeWhileM f (Stream step s n) = Stream step' s (toMax n)
   where
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' s = do
                 r <- step s
                 case r of
@@ -466,7 +471,7 @@
     -- NOTE: we jump through hoops here to have only one Yield; local data
     -- declarations would be nice!
 
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' (DropWhile_Drop s)
       = do
           r <- step s
@@ -597,6 +602,11 @@
                        Skip    s' -> foldl1M_go s'
                        Done       -> errorEmptyStream "foldl1M"
 
+-- | Same as 'foldl1M'
+fold1M :: Monad m => (a -> a -> m a) -> Stream m a -> m a
+{-# INLINE fold1M #-}
+fold1M = foldl1M
+
 -- | Left fold with a strict accumulator
 foldl' :: Monad m => (a -> b -> a) -> a -> Stream m b -> m a
 {-# INLINE foldl' #-}
@@ -615,6 +625,11 @@
                          Skip    s' -> foldlM'_go z s'
                          Done       -> return z
 
+-- | Same as 'foldlM''
+foldM' :: Monad m => (a -> b -> m a) -> a -> Stream m b -> m a
+{-# INLINE foldM' #-}
+foldM' = foldlM'
+
 -- | Left fold over a non-empty 'Stream' with a strict accumulator
 foldl1' :: Monad m => (a -> a -> a) -> Stream m a -> m a
 {-# INLINE foldl1' #-}
@@ -633,6 +648,11 @@
                         Skip    s' -> foldl1M'_go s'
                         Done       -> errorEmptyStream "foldl1M'"
 
+-- | Same as 'foldl1M''
+fold1M' :: Monad m => (a -> a -> m a) -> Stream m a -> m a
+{-# INLINE fold1M' #-}
+fold1M' = foldl1M'
+
 -- | Right fold
 foldr :: Monad m => (a -> b -> b) -> b -> Stream m a -> m b
 {-# INLINE foldr #-}
@@ -737,7 +757,7 @@
 {-# INLINE_STREAM unfoldrM #-}
 unfoldrM f s = Stream step s Unknown
   where
-    {-# INLINE step #-}
+    {-# INLINE_INNER step #-}
     step s = liftM (\r ->
                case r of
                  Just (x, s') -> Yield x s'
@@ -757,7 +777,7 @@
 {-# INLINE_STREAM prescanlM #-}
 prescanlM f z (Stream step s sz) = Stream step' (s,z) sz
   where
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' (s,x) = do
                     r <- step s
                     case r of
@@ -777,7 +797,7 @@
 {-# INLINE_STREAM prescanlM' #-}
 prescanlM' f z (Stream step s sz) = Stream step' (s,z) sz
   where
-    {-# INLINE step' #-}
+    {-# INLINE_INNER step' #-}
     step' (s,x) = x `seq`
                   do
                     r <- step s
@@ -787,6 +807,123 @@
                                       return $ Yield x (s', z)
                       Skip    s' -> return $ Skip (s', x)
                       Done       -> return Done
+
+-- | Suffix scan
+postscanl :: Monad m => (a -> b -> a) -> a -> Stream m b -> Stream m a
+{-# INLINE postscanl #-}
+postscanl f = postscanlM (\a b -> return (f a b))
+
+-- | Suffix scan with a monadic operator
+postscanlM :: Monad m => (a -> b -> m a) -> a -> Stream m b -> Stream m a
+{-# INLINE_STREAM postscanlM #-}
+postscanlM f z (Stream step s sz) = Stream step' (s,z) sz
+  where
+    {-# INLINE_INNER step' #-}
+    step' (s,x) = do
+                    r <- step s
+                    case r of
+                      Yield y s' -> do
+                                      z <- f x y
+                                      return $ Yield z (s',z)
+                      Skip    s' -> return $ Skip (s',x)
+                      Done       -> return Done
+
+-- | Suffix scan with strict accumulator
+postscanl' :: Monad m => (a -> b -> a) -> a -> Stream m b -> Stream m a
+{-# INLINE postscanl' #-}
+postscanl' f = postscanlM' (\a b -> return (f a b))
+
+-- | Suffix scan with strict acccumulator and a monadic operator
+postscanlM' :: Monad m => (a -> b -> m a) -> a -> Stream m b -> Stream m a
+{-# INLINE_STREAM postscanlM' #-}
+postscanlM' f z (Stream step s sz) = z `seq` Stream step' (s,z) sz
+  where
+    {-# INLINE_INNER step' #-}
+    step' (s,x) = x `seq`
+                  do
+                    r <- step s
+                    case r of
+                      Yield y s' -> do
+                                      z <- f x y
+                                      z `seq` return (Yield z (s',z))
+                      Skip    s' -> return $ Skip (s',x)
+                      Done       -> return Done
+
+-- | Haskell-style scan
+scanl :: Monad m => (a -> b -> a) -> a -> Stream m b -> Stream m a
+{-# INLINE scanl #-}
+scanl f = scanlM (\a b -> return (f a b))
+
+-- | Haskell-style scan with a monadic operator
+scanlM :: Monad m => (a -> b -> m a) -> a -> Stream m b -> Stream m a
+{-# INLINE scanlM #-}
+scanlM f z s = z `cons` postscanlM f z s
+
+-- | Haskell-style scan with strict accumulator
+scanl' :: Monad m => (a -> b -> a) -> a -> Stream m b -> Stream m a
+{-# INLINE scanl' #-}
+scanl' f = scanlM' (\a b -> return (f a b))
+
+-- | Haskell-style scan with strict accumulator and a monadic operator
+scanlM' :: Monad m => (a -> b -> m a) -> a -> Stream m b -> Stream m a
+{-# INLINE scanlM' #-}
+scanlM' f z s = z `seq` (z `cons` postscanlM f z s)
+
+-- | Scan over a non-empty 'Stream'
+scanl1 :: Monad m => (a -> a -> a) -> Stream m a -> Stream m a
+{-# INLINE scanl1 #-}
+scanl1 f = scanl1M (\x y -> return (f x y))
+
+-- | Scan over a non-empty 'Stream' with a monadic operator
+scanl1M :: Monad m => (a -> a -> m a) -> Stream m a -> Stream m a
+{-# INLINE_STREAM scanl1M #-}
+scanl1M f (Stream step s sz) = Stream step' (s, Nothing) sz
+  where
+    {-# INLINE_INNER step' #-}
+    step' (s, Nothing) = do
+                           r <- step s
+                           case r of
+                             Yield x s' -> return $ Yield x (s', Just x)
+                             Skip    s' -> return $ Skip (s', Nothing)
+                             Done       -> errorEmptyStream "scanl1M"
+
+    step' (s, Just x) = do
+                          r <- step s
+                          case r of
+                            Yield y s' -> do
+                                            z <- f x y
+                                            return $ Yield z (s', Just z)
+                            Skip    s' -> return $ Skip (s', Just x)
+                            Done       -> return Done
+
+-- | Scan over a non-empty 'Stream' with a strict accumulator
+scanl1' :: Monad m => (a -> a -> a) -> Stream m a -> Stream m a
+{-# INLINE scanl1' #-}
+scanl1' f = scanl1M' (\x y -> return (f x y))
+
+-- | Scan over a non-empty 'Stream' with a strict accumulator and a monadic
+-- operator
+scanl1M' :: Monad m => (a -> a -> m a) -> Stream m a -> Stream m a
+{-# INLINE_STREAM scanl1M' #-}
+scanl1M' f (Stream step s sz) = Stream step' (s, Nothing) sz
+  where
+    {-# INLINE_INNER step' #-}
+    step' (s, Nothing) = do
+                           r <- step s
+                           case r of
+                             Yield x s' -> x `seq` return (Yield x (s', Just x))
+                             Skip    s' -> return $ Skip (s', Nothing)
+                             Done       -> errorEmptyStream "scanl1M"
+
+    step' (s, Just x) = x `seq`
+                        do
+                          r <- step s
+                          case r of
+                            Yield y s' -> do
+                                            z <- f x y
+                                            z `seq` return (Yield z (s', Just z))
+                            Skip    s' -> return $ Skip (s', Just x)
+                            Done       -> return Done
 
 -- Conversions
 -- -----------
diff --git a/Data/Vector/Fusion/Stream/Size.hs b/Data/Vector/Fusion/Stream/Size.hs
--- a/Data/Vector/Fusion/Stream/Size.hs
+++ b/Data/Vector/Fusion/Stream/Size.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Vector.Fusion.Stream.Size
--- Copyright   : (c) Roman Leshchinskiy 2008
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
diff --git a/Data/Vector/Generic.hs b/Data/Vector/Generic.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Generic.hs
@@ -0,0 +1,647 @@
+{-# LANGUAGE Rank2Types, MultiParamTypeClasses, FlexibleContexts,
+             ScopedTypeVariables #-}
+-- |
+-- Module      : Data.Vector.Generic
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- Generic interface to pure vectors
+--
+
+#include "phases.h"
+
+module Data.Vector.Generic (
+  -- * Immutable vectors
+  Vector(..),
+
+  -- * Length information
+  length, null,
+
+  -- * Construction
+  empty, singleton, cons, snoc, replicate, (++), copy,
+
+  -- * Accessing individual elements
+  (!), head, last, indexM, headM, lastM,
+
+  -- * Subvectors
+  slice, init, tail, take, drop,
+
+  -- * Permutations
+  accum, (//), update, backpermute, reverse,
+
+  -- * Mapping
+  map, concatMap,
+
+  -- * Zipping and unzipping
+  zipWith, zipWith3, zip, zip3, unzip, unzip3,
+
+  -- * Comparisons
+  eq, cmp,
+
+  -- * Filtering
+  filter, takeWhile, dropWhile,
+
+  -- * Searching
+  elem, notElem, find, findIndex,
+
+  -- * Folding
+  foldl, foldl1, foldl', foldl1', foldr, foldr1,
+ 
+  -- * Specialised folds
+  and, or, sum, product, maximum, minimum,
+
+  -- * Unfolding
+  unfoldr,
+
+  -- * Scans
+  prescanl, prescanl',
+  postscanl, postscanl',
+  scanl, scanl', scanl1, scanl1',
+
+  -- * Enumeration
+  enumFromTo, enumFromThenTo,
+
+  -- * Conversion to/from lists
+  toList, fromList,
+
+  -- * Conversion to/from Streams
+  stream, unstream,
+
+  -- * MVector-based initialisation
+  new
+) where
+
+import           Data.Vector.Generic.Mutable ( MVector )
+
+import qualified Data.Vector.Generic.New as New
+import           Data.Vector.Generic.New ( New )
+
+import qualified Data.Vector.Fusion.Stream as Stream
+import           Data.Vector.Fusion.Stream ( Stream, MStream, inplace, inplace' )
+import qualified Data.Vector.Fusion.Stream.Monadic as MStream
+import           Data.Vector.Fusion.Stream.Size
+import           Data.Vector.Fusion.Util
+
+import Control.Exception ( assert )
+
+import Prelude hiding ( length, null,
+                        replicate, (++),
+                        head, last,
+                        init, tail, take, drop, reverse,
+                        map, concatMap,
+                        zipWith, zipWith3, zip, zip3, unzip, unzip3,
+                        filter, takeWhile, dropWhile,
+                        elem, notElem,
+                        foldl, foldl1, foldr, foldr1,
+                        and, or, sum, product, maximum, minimum,
+                        scanl, scanl1,
+                        enumFromTo, enumFromThenTo )
+
+-- | Class of immutable vectors.
+--
+class Vector v a where
+  -- | Construct a pure vector from a monadic initialiser (not fusible!)
+  vnew         :: (forall mv m. MVector mv m a => m (mv a)) -> v a
+
+  -- | Length of the vector (not fusible!)
+  vlength      :: v a -> Int
+
+  -- | Yield a part of the vector without copying it. No range checks!
+  unsafeSlice  :: v a -> Int -> Int -> v a
+
+  -- | Yield the element at the given position in a monad. The monad allows us
+  -- to be strict in the vector if we want. Suppose we had
+  --
+  -- > unsafeIndex :: v a -> Int -> a
+  --
+  -- instead. Now, if we wanted to copy a vector, we'd do something like
+  --
+  -- > copy mv v ... = ... unsafeWrite mv i (unsafeIndex v i) ...
+  --
+  -- For lazy vectors, the indexing would not be evaluated which means that we
+  -- would retain a reference to the original vector in each element we write.
+  -- This is not what we want!
+  --
+  -- With 'unsafeIndexM', we can do
+  --
+  -- > copy mv v ... = ... case unsafeIndexM v i of
+  -- >                       Box x -> unsafeWrite mv i x ...
+  --
+  -- which does not have this problem because indexing (but not the returned
+  -- element!) is evaluated immediately.
+  --
+  unsafeIndexM  :: Monad m => v a -> Int -> m a
+
+-- Fusion
+-- ------
+
+-- | Construct a pure vector from a monadic initialiser 
+new :: Vector v a => New a -> v a
+{-# INLINE new #-}
+new m = new' undefined m
+
+-- | Same as 'new' but with a dummy argument necessary for correctly typing
+-- the rule @uninplace@.
+--
+-- See http://hackage.haskell.org/trac/ghc/ticket/2600
+new' :: Vector v a => v a -> New a -> v a
+{-# INLINE_STREAM new' #-}
+new' _ m = vnew (New.run m)
+
+-- | Convert a vector to a 'Stream'
+stream :: Vector v a => v a -> Stream a
+{-# INLINE_STREAM stream #-}
+stream v = v `seq` (Stream.unfoldr get 0 `Stream.sized` Exact n)
+  where
+    n = length v
+
+    {-# INLINE get #-}
+    get i | i < n     = case unsafeIndexM v i of Box x -> Just (x, i+1)
+          | otherwise = Nothing
+
+-- | Create a vector from a 'Stream'
+unstream :: Vector v a => Stream a -> v a
+{-# INLINE unstream #-}
+unstream s = new (New.unstream s)
+
+{-# RULES
+
+"stream/unstream [Vector]" forall v s.
+  stream (new' v (New.unstream s)) = s
+
+"New.unstream/stream/new [Vector]" forall v p.
+  New.unstream (stream (new' v p)) = p
+
+ #-}
+
+{-# RULES
+
+"inplace [Vector]"
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a) v m.
+  New.unstream (inplace f (stream (new' v m))) = New.transform f m
+
+"uninplace [Vector]"
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a) v m.
+  stream (new' v (New.transform f m)) = inplace f (stream (new' v m))
+
+ #-}
+
+-- Length
+-- ------
+
+length :: Vector v a => v a -> Int
+{-# INLINE_STREAM length #-}
+length v = vlength v
+
+{-# RULES
+
+"length/unstream [Vector]" forall v s.
+  length (new' v (New.unstream s)) = Stream.length s
+
+  #-}
+
+null :: Vector v a => v a -> Bool
+{-# INLINE_STREAM null #-}
+null v = vlength v == 0
+
+{-# RULES
+
+"null/unstream [Vector]" forall v s.
+  null (new' v (New.unstream s)) = Stream.null s
+
+  #-}
+
+-- Construction
+-- ------------
+
+-- | Empty vector
+empty :: Vector v a => v a
+{-# INLINE empty #-}
+empty = unstream Stream.empty
+
+-- | Vector with exaclty one element
+singleton :: Vector v a => a -> v a
+{-# INLINE singleton #-}
+singleton x = unstream (Stream.singleton x)
+
+-- | Vector of the given length with the given value in each position
+replicate :: Vector v a => Int -> a -> v a
+{-# INLINE replicate #-}
+replicate n = unstream . Stream.replicate n
+
+-- | Prepend an element
+cons :: Vector v a => a -> v a -> v a
+{-# INLINE cons #-}
+cons x = unstream . Stream.cons x . stream
+
+-- | Append an element
+snoc :: Vector v a => v a -> a -> v a
+{-# INLINE snoc #-}
+snoc v = unstream . Stream.snoc (stream v)
+
+infixr 5 ++
+-- | Concatenate two vectors
+(++) :: Vector v a => v a -> v a -> v a
+{-# INLINE (++) #-}
+v ++ w = unstream (stream v Stream.++ stream w)
+
+-- | Create a copy of a vector. Useful when dealing with slices.
+copy :: Vector v a => v a -> v a
+{-# INLINE_STREAM copy #-}
+copy = unstream . stream
+
+{-# RULES
+
+"copy/unstream [Vector]" forall v s.
+  copy (new' v (New.unstream s)) = new' v (New.unstream s)
+
+ #-}
+
+-- Accessing individual elements
+-- -----------------------------
+
+-- | Indexing
+(!) :: Vector v a => v a -> Int -> a
+{-# INLINE_STREAM (!) #-}
+v ! i = assert (i >= 0 && i < length v)
+      $ unId (unsafeIndexM v i)
+
+-- | First element
+head :: Vector v a => v a -> a
+{-# INLINE_STREAM head #-}
+head v = v ! 0
+
+-- | Last element
+last :: Vector v a => v a -> a
+{-# INLINE_STREAM last #-}
+last v = v ! (length v - 1)
+
+{-# RULES
+
+"(!)/unstream [Vector]" forall v i s.
+  new' v (New.unstream s) ! i = s Stream.!! i
+
+"head/unstream [Vector]" forall v s.
+  head (new' v (New.unstream s)) = Stream.head s
+
+"last/unstream [Vector]" forall v s.
+  last (new' v (New.unstream s)) = Stream.last s
+
+ #-}
+
+-- | Monadic indexing which can be strict in the vector while remaining lazy in
+-- the element.
+indexM :: (Vector v a, Monad m) => v a -> Int -> m a
+{-# INLINE_STREAM indexM #-}
+indexM v i = assert (i >= 0 && i < length v)
+           $ unsafeIndexM v i
+
+headM :: (Vector v a, Monad m) => v a -> m a
+{-# INLINE_STREAM headM #-}
+headM v = indexM v 0
+
+lastM :: (Vector v a, Monad m) => v a -> m a
+{-# INLINE_STREAM lastM #-}
+lastM v = indexM v (length v - 1)
+
+-- FIXME: the rhs of these rules are lazy in the stream which is WRONG
+{- RULES
+
+"indexM/unstream [Vector]" forall v i s.
+  indexM (new' v (New.unstream s)) i = return (s Stream.!! i)
+
+"headM/unstream [Vector]" forall v s.
+  headM (new' v (New.unstream s)) = return (Stream.head s)
+
+"lastM/unstream [Vector]" forall v s.
+  lastM (new' v (New.unstream s)) = return (Stream.last s)
+
+ -}
+
+-- Subarrays
+-- ---------
+
+-- FIXME: slicing doesn't work with the inplace stuff at the moment
+
+-- | Yield a part of the vector without copying it. Safer version of
+-- 'unsafeSlice'.
+slice :: Vector v a => v a -> Int   -- ^ starting index
+                            -> Int   -- ^ length
+                            -> v a
+{-# INLINE_STREAM slice #-}
+slice v i n = assert (i >= 0 && n >= 0  && i+n <= length v)
+            $ unsafeSlice v i n
+
+-- | Yield all but the last element without copying.
+init :: Vector v a => v a -> v a
+{-# INLINE_STREAM init #-}
+init v = slice v 0 (length v - 1)
+
+-- | All but the first element (without copying).
+tail :: Vector v a => v a -> v a
+{-# INLINE_STREAM tail #-}
+tail v = slice v 1 (length v - 1)
+
+-- | Yield the first @n@ elements without copying.
+take :: Vector v a => Int -> v a -> v a
+{-# INLINE_STREAM take #-}
+take n v = slice v 0 (min n' (length v))
+  where n' = max n 0
+
+-- | Yield all but the first @n@ elements without copying.
+drop :: Vector v a => Int -> v a -> v a
+{-# INLINE_STREAM drop #-}
+drop n v = slice v (min n' len) (max 0 (len - n'))
+  where n' = max n 0
+        len = length v
+
+{-# RULES
+
+"slice/new [Vector]" forall v p i n.
+  slice (new' v p) i n = new' v (New.slice p i n)
+
+"init/new [Vector]" forall v p.
+  init (new' v p) = new' v (New.init p)
+
+"tail/new [Vector]" forall v p.
+  tail (new' v p) = new' v (New.tail p)
+
+"take/new [Vector]" forall n v p.
+  take n (new' v p) = new' v (New.take n p)
+
+"drop/new [Vector]" forall n v p.
+  drop n (new' v p) = new' v (New.drop n p)
+
+  #-}
+
+-- Permutations
+-- ------------
+
+accum :: Vector v a => (a -> b -> a) -> v a -> [(Int,b)] -> v a
+{-# INLINE accum #-}
+accum f v us = new (New.accum f (New.unstream (stream v))
+                                (Stream.fromList us))
+
+(//) :: Vector v a => v a -> [(Int, a)] -> v a
+{-# INLINE (//) #-}
+v // us = new (New.update (New.unstream (stream v))
+                          (Stream.fromList us))
+
+update :: (Vector v a, Vector v (Int, a)) => v a -> v (Int, a) -> v a
+{-# INLINE update #-}
+update v w = new (New.update (New.unstream (stream v)) (stream w))
+
+-- This somewhat non-intuitive definition ensures that the resulting vector
+-- does not retain references to the original one even if it is lazy in its
+-- elements. This would not be the case if we simply used
+--
+-- backpermute v is = map (v!) is
+backpermute :: (Vector v a, Vector v Int) => v a -> v Int -> v a
+{-# INLINE backpermute #-}
+backpermute v is = seq v
+                 $ unstream
+                 $ MStream.trans (Id . unBox)
+                 $ MStream.mapM (indexM v)
+                 $ MStream.trans (Box . unId)
+                 $ stream is
+
+reverse :: (Vector v a) => v a -> v a
+{-# INLINE reverse #-}
+reverse = new . New.reverse . New.unstream . stream
+
+-- Mapping
+-- -------
+
+-- | Map a function over a vector
+map :: (Vector v a, Vector v b) => (a -> b) -> v a -> v b
+{-# INLINE map #-}
+map f = unstream . inplace' (MStream.map f) . stream
+
+concatMap :: (Vector v a, Vector v b) => (a -> v b) -> v a -> v b
+{-# INLINE concatMap #-}
+concatMap f = unstream . Stream.concatMap (stream . f) . stream
+
+-- Zipping/unzipping
+-- -----------------
+
+-- | Zip two vectors with the given function.
+zipWith :: (Vector v a, Vector v b, Vector v c) => (a -> b -> c) -> v a -> v b -> v c
+{-# INLINE zipWith #-}
+zipWith f xs ys = unstream (Stream.zipWith f (stream xs) (stream ys))
+
+-- | Zip three vectors with the given function.
+zipWith3 :: (Vector v a, Vector v b, Vector v c, Vector v d) => (a -> b -> c -> d) -> v a -> v b -> v c -> v d
+{-# INLINE zipWith3 #-}
+zipWith3 f xs ys zs = unstream (Stream.zipWith3 f (stream xs) (stream ys) (stream zs))
+
+zip :: (Vector v a, Vector v b, Vector v (a,b)) => v a -> v b -> v (a, b)
+{-# INLINE zip #-}
+zip = zipWith (,)
+
+zip3 :: (Vector v a, Vector v b, Vector v c, Vector v (a, b, c)) => v a -> v b -> v c -> v (a, b, c)
+{-# INLINE zip3 #-}
+zip3 = zipWith3 (,,)
+
+unzip :: (Vector v a, Vector v b, Vector v (a,b)) => v (a, b) -> (v a, v b)
+{-# INLINE unzip #-}
+unzip xs = (map fst xs, map snd xs)
+
+unzip3 :: (Vector v a, Vector v b, Vector v c, Vector v (a, b, c)) => v (a, b, c) -> (v a, v b, v c)
+{-# INLINE unzip3 #-}
+unzip3 xs = (map (\(a, b, c) -> a) xs, map (\(a, b, c) -> b) xs, map (\(a, b, c) -> c) xs)
+
+-- Comparisons
+-- -----------
+
+eq :: (Vector v a, Eq a) => v a -> v a -> Bool
+{-# INLINE eq #-}
+xs `eq` ys = stream xs == stream ys
+
+cmp :: (Vector v a, Ord a) => v a -> v a -> Ordering
+{-# INLINE cmp #-}
+cmp xs ys = compare (stream xs) (stream ys)
+
+-- Filtering
+-- ---------
+
+-- | Drop elements which do not satisfy the predicate
+filter :: Vector v a => (a -> Bool) -> v a -> v a
+{-# INLINE filter #-}
+filter f = unstream . inplace (MStream.filter f) . stream
+
+-- | Yield the longest prefix of elements satisfying the predicate.
+takeWhile :: Vector v a => (a -> Bool) -> v a -> v a
+{-# INLINE takeWhile #-}
+takeWhile f = unstream . Stream.takeWhile f . stream
+
+-- | Drop the longest prefix of elements that satisfy the predicate.
+dropWhile :: Vector v a => (a -> Bool) -> v a -> v a
+{-# INLINE dropWhile #-}
+dropWhile f = unstream . Stream.dropWhile f . stream
+
+-- Searching
+-- ---------
+
+infix 4 `elem`
+-- | Check whether the vector contains an element
+elem :: (Vector v a, Eq a) => a -> v a -> Bool
+{-# INLINE elem #-}
+elem x = Stream.elem x . stream
+
+infix 4 `notElem`
+-- | Inverse of `elem`
+notElem :: (Vector v a, Eq a) => a -> v a -> Bool
+{-# INLINE notElem #-}
+notElem x = Stream.notElem x . stream
+
+-- | Yield 'Just' the first element matching the predicate or 'Nothing' if no
+-- such element exists.
+find :: Vector v a => (a -> Bool) -> v a -> Maybe a
+{-# INLINE find #-}
+find f = Stream.find f . stream
+
+-- | Yield 'Just' the index of the first element matching the predicate or
+-- 'Nothing' if no such element exists.
+findIndex :: Vector v a => (a -> Bool) -> v a -> Maybe Int
+{-# INLINE findIndex #-}
+findIndex f = Stream.findIndex f . stream
+
+-- Folding
+-- -------
+
+-- | Left fold
+foldl :: Vector v b => (a -> b -> a) -> a -> v b -> a
+{-# INLINE foldl #-}
+foldl f z = Stream.foldl f z . stream
+
+-- | Lefgt fold on non-empty vectors
+foldl1 :: Vector v a => (a -> a -> a) -> v a -> a
+{-# INLINE foldl1 #-}
+foldl1 f = Stream.foldl1 f . stream
+
+-- | Left fold with strict accumulator
+foldl' :: Vector v b => (a -> b -> a) -> a -> v b -> a
+{-# INLINE foldl' #-}
+foldl' f z = Stream.foldl' f z . stream
+
+-- | Left fold on non-empty vectors with strict accumulator
+foldl1' :: Vector v a => (a -> a -> a) -> v a -> a
+{-# INLINE foldl1' #-}
+foldl1' f = Stream.foldl1' f . stream
+
+-- | Right fold
+foldr :: Vector v a => (a -> b -> b) -> b -> v a -> b
+{-# INLINE foldr #-}
+foldr f z = Stream.foldr f z . stream
+
+-- | Right fold on non-empty vectors
+foldr1 :: Vector v a => (a -> a -> a) -> v a -> a
+{-# INLINE foldr1 #-}
+foldr1 f = Stream.foldr1 f . stream
+
+-- Specialised folds
+-- -----------------
+
+and :: Vector v Bool => v Bool -> Bool
+{-# INLINE and #-}
+and = Stream.and . stream
+
+or :: Vector v Bool => v Bool -> Bool
+{-# INLINE or #-}
+or = Stream.or . stream
+
+sum :: (Vector v a, Num a) => v a -> a
+{-# INLINE sum #-}
+sum = Stream.foldl' (+) 0 . stream
+
+product :: (Vector v a, Num a) => v a -> a
+{-# INLINE product #-}
+product = Stream.foldl' (*) 1 . stream
+
+maximum :: (Vector v a, Ord a) => v a -> a
+{-# INLINE maximum #-}
+maximum = Stream.foldl1' max . stream
+
+minimum :: (Vector v a, Ord a) => v a -> a
+{-# INLINE minimum #-}
+minimum = Stream.foldl1' min . stream
+
+-- Unfolding
+-- ---------
+
+unfoldr :: Vector v a => (b -> Maybe (a, b)) -> b -> v a
+{-# INLINE unfoldr #-}
+unfoldr f = unstream . Stream.unfoldr f
+
+-- Scans
+-- -----
+
+-- | Prefix scan
+prescanl :: (Vector v a, Vector v b) => (a -> b -> a) -> a -> v b -> v a
+{-# INLINE prescanl #-}
+prescanl f z = unstream . inplace' (MStream.prescanl f z) . stream
+
+-- | Prefix scan with strict accumulator
+prescanl' :: (Vector v a, Vector v b) => (a -> b -> a) -> a -> v b -> v a
+{-# INLINE prescanl' #-}
+prescanl' f z = unstream . inplace' (MStream.prescanl' f z) . stream
+
+-- | Suffix scan
+postscanl :: (Vector v a, Vector v b) => (a -> b -> a) -> a -> v b -> v a
+{-# INLINE postscanl #-}
+postscanl f z = unstream . inplace' (MStream.postscanl f z) . stream
+
+-- | Suffix scan with strict accumulator
+postscanl' :: (Vector v a, Vector v b) => (a -> b -> a) -> a -> v b -> v a
+{-# INLINE postscanl' #-}
+postscanl' f z = unstream . inplace' (MStream.postscanl' f z) . stream
+
+-- | Haskell-style scan
+scanl :: (Vector v a, Vector v b) => (a -> b -> a) -> a -> v b -> v a
+{-# INLINE scanl #-}
+scanl f z = unstream . Stream.scanl f z . stream
+
+-- | Haskell-style scan with strict accumulator
+scanl' :: (Vector v a, Vector v b) => (a -> b -> a) -> a -> v b -> v a
+{-# INLINE scanl' #-}
+scanl' f z = unstream . Stream.scanl' f z . stream
+
+-- | Scan over a non-empty vector
+scanl1 :: Vector v a => (a -> a -> a) -> v a -> v a
+{-# INLINE scanl1 #-}
+scanl1 f = unstream . inplace (MStream.scanl1 f) . stream
+
+-- | Scan over a non-empty vector with a strict accumulator
+scanl1' :: Vector v a => (a -> a -> a) -> v a -> v a
+{-# INLINE scanl1' #-}
+scanl1' f = unstream . inplace (MStream.scanl1' f) . stream
+
+-- Enumeration
+-- -----------
+
+-- FIXME: The Enum class is irreparably broken, there just doesn't seem to be a
+-- way to implement this generically. Either specialise this or define a new
+-- Enum-like class with a proper interface.
+
+enumFromTo :: (Vector v a, Enum a) => a -> a -> v a
+{-# INLINE enumFromTo #-}
+enumFromTo from to = fromList [from .. to]
+
+enumFromThenTo :: (Vector v a, Enum a) => a -> a -> a -> v a
+{-# INLINE enumFromThenTo #-}
+enumFromThenTo from next to = fromList [from, next .. to]
+
+-- | Convert a vector to a list
+toList :: Vector v a => v a -> [a]
+{-# INLINE toList #-}
+toList = Stream.toList . stream
+
+-- | Convert a list to a vector
+fromList :: Vector v a => [a] -> v a
+{-# INLINE fromList #-}
+fromList = unstream . Stream.fromList
+
diff --git a/Data/Vector/Generic/Mutable.hs b/Data/Vector/Generic/Mutable.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Generic/Mutable.hs
@@ -0,0 +1,256 @@
+{-# LANGUAGE MultiParamTypeClasses, BangPatterns #-}
+-- |
+-- Module      : Data.Vector.Generic.Mutable
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- Generic interface to mutable vectors
+--
+
+#include "phases.h"
+
+module Data.Vector.Generic.Mutable (
+  MVectorPure(..), MVector(..),
+
+  slice, new, newWith, read, write, copy, grow,
+  unstream, transform,
+  accum, update, reverse
+) where
+
+import qualified Data.Vector.Fusion.Stream      as Stream
+import           Data.Vector.Fusion.Stream      ( Stream, MStream )
+import qualified Data.Vector.Fusion.Stream.Monadic as MStream
+import           Data.Vector.Fusion.Stream.Size
+
+import Control.Exception ( assert )
+
+import GHC.Float (
+    double2Int, int2Double
+  )
+
+import Prelude hiding ( length, reverse, map, read )
+
+gROWTH_FACTOR :: Double
+gROWTH_FACTOR = 1.5
+
+-- | Basic pure functions on mutable vectors
+class MVectorPure v a where
+  -- | Length of the mutable vector
+  length           :: v a -> Int
+
+  -- | Yield a part of the mutable vector without copying it. No range checks!
+  unsafeSlice      :: v a -> Int  -- ^ starting index
+                          -> Int  -- ^ length of the slice
+                          -> v a
+
+  -- Check whether two vectors overlap.
+  overlaps         :: v a -> v a -> Bool
+
+-- | Class of mutable vectors. The type @m@ is the monad in which the mutable
+-- vector can be transformed and @a@ is the type of elements.
+--
+class (Monad m, MVectorPure v a) => MVector v m a where
+  -- | Create a mutable vector of the given length. Length is not checked!
+  unsafeNew        :: Int -> m (v a)
+
+  -- | Create a mutable vector of the given length and fill it with an
+  -- initial value. Length is not checked!
+  unsafeNewWith    :: Int -> a -> m (v a)
+
+  -- | Yield the element at the given position. Index is not checked!
+  unsafeRead       :: v a -> Int -> m a
+
+  -- | Replace the element at the given position. Index is not checked!
+  unsafeWrite      :: v a -> Int -> a -> m ()
+
+  -- | Clear all references to external objects
+  clear            :: v a -> m ()
+
+  -- | Write the value at each position.
+  set              :: v a -> a -> m ()
+
+  -- | Copy a vector. The two vectors may not overlap. This is not checked!
+  unsafeCopy       :: v a   -- ^ target
+                   -> v a   -- ^ source
+                   -> m ()
+
+  -- | Grow a vector by the given number of elements. The length is not
+  -- checked!
+  unsafeGrow       :: v a -> Int -> m (v a)
+
+  {-# INLINE unsafeNewWith #-}
+  unsafeNewWith n x = do
+                        v <- unsafeNew n
+                        set v x
+                        return v
+
+  {-# INLINE set #-}
+  set v x = do_set 0
+    where
+      n = length v
+
+      do_set i | i < n = do
+                            unsafeWrite v i x
+                            do_set (i+1)
+                | otherwise = return ()
+
+  {-# INLINE unsafeCopy #-}
+  unsafeCopy dst src = do_copy 0
+    where
+      n = length src
+
+      do_copy i | i < n = do
+                            x <- unsafeRead src i
+                            unsafeWrite dst i x
+                            do_copy (i+1)
+                | otherwise = return ()
+
+  {-# INLINE unsafeGrow #-}
+  unsafeGrow v by = do
+                      v' <- unsafeNew (n+by)
+                      unsafeCopy (unsafeSlice v' 0 n) v
+                      return v'
+    where
+      n = length v
+
+-- | Test whether the index is valid for the vector
+inBounds :: MVectorPure v a => v a -> Int -> Bool
+{-# INLINE inBounds #-}
+inBounds v i = i >= 0 && i < length v
+
+-- | Yield a part of the mutable vector without copying it. Safer version of
+-- 'unsafeSlice'.
+slice :: MVectorPure v a => v a -> Int -> Int -> v a
+{-# INLINE slice #-}
+slice v i n = assert (i >=0 && n >= 0 && i+n <= length v)
+            $ unsafeSlice v i n
+
+-- | Create a mutable vector of the given length. Safer version of
+-- 'unsafeNew'.
+new :: MVector v m a => Int -> m (v a)
+{-# INLINE new #-}
+new n = assert (n >= 0) $ unsafeNew n
+
+-- | Create a mutable vector of the given length and fill it with an
+-- initial value. Safer version of 'unsafeNewWith'.
+newWith :: MVector v m a => Int -> a -> m (v a)
+{-# INLINE newWith #-}
+newWith n x = assert (n >= 0) $ unsafeNewWith n x
+
+-- | Yield the element at the given position. Safer version of 'unsafeRead'.
+read :: MVector v m a => v a -> Int -> m a
+{-# INLINE read #-}
+read v i = assert (inBounds v i) $ unsafeRead v i
+
+-- | Replace the element at the given position. Safer version of
+-- 'unsafeWrite'.
+write :: MVector v m a => v a -> Int -> a -> m ()
+{-# INLINE write #-}
+write v i x = assert (inBounds v i) $ unsafeWrite v i x
+
+-- | Copy a vector. The two vectors may not overlap. Safer version of
+-- 'unsafeCopy'.
+copy :: MVector v m a => v a -> v a -> m ()
+{-# INLINE copy #-}
+copy dst src = assert (not (dst `overlaps` src) && length dst == length src)
+             $ unsafeCopy dst src
+
+-- | Grow a vector by the given number of elements. Safer version of
+-- 'unsafeGrow'.
+grow :: MVector v m a => v a -> Int -> m (v a)
+{-# INLINE grow #-}
+grow v by = assert (by >= 0)
+          $ unsafeGrow v by
+
+mstream :: MVector v m a => v a -> MStream m a
+{-# INLINE mstream #-}
+mstream v = v `seq` (MStream.unfoldrM get 0 `MStream.sized` Exact n)
+  where
+    n = length v
+
+    {-# INLINE_INNER get #-}
+    get i | i < n     = do x <- unsafeRead v i
+                           return $ Just (x, i+1)
+          | otherwise = return $ Nothing
+
+munstream :: MVector v m a => v a -> MStream m a -> m (v a)
+{-# INLINE munstream #-}
+munstream v s = v `seq` do
+                          n' <- MStream.foldM put 0 s
+                          return $ slice v 0 n'
+  where
+    {-# INLINE_INNER put #-}
+    put i x = do { write v i x; return (i+1) }
+
+transform :: MVector v m a => (MStream m a -> MStream m a) -> v a -> m (v a)
+{-# INLINE_STREAM transform #-}
+transform f v = munstream v (f (mstream v))
+
+-- | Create a new mutable vector and fill it with elements from the 'Stream'.
+-- The vector will grow logarithmically if the 'Size' hint of the 'Stream' is
+-- inexact.
+unstream :: MVector v m a => Stream a -> m (v a)
+{-# INLINE_STREAM unstream #-}
+unstream s = case upperBound (Stream.size s) of
+               Just n  -> unstreamMax     s n
+               Nothing -> unstreamUnknown s
+
+unstreamMax :: MVector v m a => Stream a -> Int -> m (v a)
+{-# INLINE unstreamMax #-}
+unstreamMax s n
+  = do
+      v  <- new n
+      let put i x = do { write v i x; return (i+1) }
+      n' <- Stream.foldM' put 0 s
+      return $ slice v 0 n'
+
+unstreamUnknown :: MVector v m a => Stream a -> m (v a)
+{-# INLINE unstreamUnknown #-}
+unstreamUnknown s
+  = do
+      v <- new 0
+      (v', n) <- Stream.foldM put (v, 0) s
+      return $ slice v' 0 n
+  where
+    {-# INLINE_INNER put #-}
+    put (v, i) x = do
+                     v' <- enlarge v i
+                     unsafeWrite v' i x
+                     return (v', i+1)
+
+    {-# INLINE_INNER enlarge #-}
+    enlarge v i | i < length v = return v
+                | otherwise    = unsafeGrow v
+                                 . max 1
+                                 . double2Int
+                                 $ int2Double (length v) * gROWTH_FACTOR
+
+accum :: MVector v m a => (a -> b -> a) -> v a -> Stream (Int, b) -> m ()
+{-# INLINE accum #-}
+accum f !v s = Stream.mapM_ upd s
+  where
+    {-# INLINE_INNER upd #-}
+    upd (i,b) = do
+                  a <- read v i
+                  write v i (f a b)
+
+update :: MVector v m a => v a -> Stream (Int, a) -> m ()
+{-# INLINE update #-}
+update = accum (const id)
+
+reverse :: MVector v m a => v a -> m ()
+{-# INLINE reverse #-}
+reverse !v = reverse_loop 0 (length v - 1)
+  where
+    reverse_loop i j | i < j = do
+                                 x <- unsafeRead v i
+                                 y <- unsafeRead v j
+                                 unsafeWrite v i y
+                                 unsafeWrite v j x
+                                 reverse_loop (i + 1) (j - 1)
+    reverse_loop _ _ = return ()
+
diff --git a/Data/Vector/Generic/New.hs b/Data/Vector/Generic/New.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Generic/New.hs
@@ -0,0 +1,118 @@
+{-# LANGUAGE Rank2Types #-}
+
+-- |
+-- Module      : Data.Vector.Generic.New
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- Purely functional interface to initialisation of mutable vectors
+--
+
+#include "phases.h"
+
+module Data.Vector.Generic.New (
+  New(..), run, unstream, transform, accum, update, reverse,
+  slice, init, tail, take, drop
+) where
+
+import qualified Data.Vector.Generic.Mutable as MVector
+import           Data.Vector.Generic.Mutable ( MVector, MVectorPure )
+
+import           Data.Vector.Fusion.Stream ( Stream, MStream )
+import qualified Data.Vector.Fusion.Stream as Stream
+
+import Control.Monad  ( liftM )
+import Prelude hiding ( init, tail, take, drop, reverse, map, filter )
+
+newtype New a = New (forall m mv. MVector mv m a => m (mv a))
+
+run :: MVector mv m a => New a -> m (mv a)
+{-# INLINE run #-}
+run (New p) = p
+
+apply :: (forall mv a. MVectorPure mv a => mv a -> mv a) -> New a -> New a
+{-# INLINE apply #-}
+apply f (New p) = New (liftM f p)
+
+modify :: New a -> (forall m mv. MVector mv m a => mv a -> m ()) -> New a
+{-# INLINE modify #-}
+modify (New p) q = New (do { v <- p; q v; return v })
+
+unstream :: Stream a -> New a
+{-# INLINE_STREAM unstream #-}
+unstream s = New (MVector.unstream s)
+
+transform :: (forall m. Monad m => MStream m a -> MStream m a) -> New a -> New a
+{-# INLINE_STREAM transform #-}
+transform f (New p) = New (MVector.transform f =<< p)
+
+{-# RULES
+
+"transform/transform [New]"
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a)
+         (g :: forall m. Monad m => MStream m a -> MStream m a)
+         p .
+  transform f (transform g p) = transform (f . g) p
+
+"transform/unstream [New]"
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a)
+         s.
+  transform f (unstream s) = unstream (f s)
+
+ #-}
+
+slice :: New a -> Int -> Int -> New a
+{-# INLINE_STREAM slice #-}
+slice m i n = apply (\v -> MVector.slice v i n) m
+
+init :: New a -> New a
+{-# INLINE_STREAM init #-}
+init m = apply (\v -> MVector.slice v 0 (MVector.length v - 1)) m
+
+tail :: New a -> New a
+{-# INLINE_STREAM tail #-}
+tail m = apply (\v -> MVector.slice v 1 (MVector.length v - 1)) m
+
+take :: Int -> New a -> New a
+{-# INLINE_STREAM take #-}
+take n m = apply (\v -> MVector.slice v 0 (min n (MVector.length v))) m
+
+drop :: Int -> New a -> New a
+{-# INLINE_STREAM drop #-}
+drop n m = apply (\v -> MVector.slice v n (max 0 (MVector.length v - n))) m
+
+{-# RULES
+
+"slice/unstream [New]" forall s i n.
+  slice (unstream s) i n = unstream (Stream.extract s i n)
+
+"init/unstream [New]" forall s.
+  init (unstream s) = unstream (Stream.init s)
+
+"tail/unstream [New]" forall s.
+  tail (unstream s) = unstream (Stream.tail s)
+
+"take/unstream [New]" forall n s.
+  take n (unstream s) = unstream (Stream.take n s)
+
+"drop/unstream [New]" forall n s.
+  drop n (unstream s) = unstream (Stream.drop n s)
+
+  #-}
+
+accum :: (a -> b -> a) -> New a -> Stream (Int, b) -> New a
+{-# INLINE_STREAM accum #-}
+accum f m s = modify m (\v -> MVector.accum f v s)
+
+update :: New a -> Stream (Int, a) -> New a
+{-# INLINE_STREAM update #-}
+update m s = modify m (\v -> MVector.update v s)
+
+reverse :: New a -> New a
+{-# INLINE_STREAM reverse #-}
+reverse m = modify m (MVector.reverse)
+
diff --git a/Data/Vector/IVector.hs b/Data/Vector/IVector.hs
deleted file mode 100644
--- a/Data/Vector/IVector.hs
+++ /dev/null
@@ -1,667 +0,0 @@
-{-# LANGUAGE Rank2Types, MultiParamTypeClasses, FlexibleContexts,
-             ScopedTypeVariables #-}
--- |
--- Module      : Data.Vector.IVector
--- Copyright   : (c) Roman Leshchinskiy 2008
--- License     : BSD-style
---
--- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
--- Stability   : experimental
--- Portability : non-portable
--- 
--- Generic interface to pure vectors
---
-
-#include "phases.h"
-
-module Data.Vector.IVector (
-  -- * Immutable vectors
-  IVector,
-
-  -- * Length information
-  length, null,
-
-  -- * Construction
-  empty, singleton, cons, snoc, replicate, (++), copy,
-
-  -- * Accessing individual elements
-  (!), head, last, indexM, headM, lastM,
-
-  -- * Subvectors
-  slice, init, tail, take, drop,
-
-  -- * Permutations
-  accum, (//), update, backpermute, reverse,
-
-  -- * Mapping
-  map, concatMap,
-
-  -- * Zipping and unzipping
-  zipWith, zipWith3, zip, zip3, unzip, unzip3,
-
-  -- * Comparisons
-  eq, cmp,
-
-  -- * Filtering
-  filter, takeWhile, dropWhile,
-
-  -- * Searching
-  elem, notElem, find, findIndex,
-
-  -- * Folding
-  foldl, foldl1, foldl', foldl1', foldr, foldr1,
- 
-  -- * Specialised folds
-  and, or, sum, product, maximum, minimum,
-
-  -- * Unfolding
-  unfoldr,
-
-  -- * Scans
-  prescanl, prescanl',
-
-  -- * Enumeration
-  enumFromTo, enumFromThenTo,
-
-  -- * Conversion to/from lists
-  toList, fromList,
-
-  -- * Conversion to/from Streams
-  stream, unstream,
-
-  -- * MVector-based initialisation
-  new,
-
-  -- * Unsafe functions
-  unsafeSlice, unsafeIndexM,
-
-  -- * Utility functions
-  vlength, vnew
-) where
-
-import qualified Data.Vector.MVector as MVector
-import           Data.Vector.MVector ( MVector )
-
-import qualified Data.Vector.MVector.New as New
-import           Data.Vector.MVector.New ( New )
-
-import qualified Data.Vector.Fusion.Stream as Stream
-import           Data.Vector.Fusion.Stream ( Stream, MStream )
-import qualified Data.Vector.Fusion.Stream.Monadic as MStream
-import           Data.Vector.Fusion.Stream.Size
-import           Data.Vector.Fusion.Util
-
-import Control.Exception ( assert )
-
-import Prelude hiding ( length, null,
-                        replicate, (++),
-                        head, last,
-                        init, tail, take, drop, reverse,
-                        map, concatMap,
-                        zipWith, zipWith3, zip, zip3, unzip, unzip3,
-                        filter, takeWhile, dropWhile,
-                        elem, notElem,
-                        foldl, foldl1, foldr, foldr1,
-                        and, or, sum, product, maximum, minimum,
-                        enumFromTo, enumFromThenTo )
-
--- | Class of immutable vectors.
---
-class IVector v a where
-  -- | Construct a pure vector from a monadic initialiser (not fusible!)
-  vnew         :: (forall mv m. MVector mv m a => m (mv a)) -> v a
-
-  -- | Length of the vector (not fusible!)
-  vlength      :: v a -> Int
-
-  -- | Yield a part of the vector without copying it. No range checks!
-  unsafeSlice  :: v a -> Int -> Int -> v a
-
-  -- | Yield the element at the given position in a monad. The monad allows us
-  -- to be strict in the vector if we want. Suppose we had
-  --
-  -- > unsafeIndex :: v a -> Int -> a
-  --
-  -- instead. Now, if we wanted to copy a vector, we'd do something like
-  --
-  -- > copy mv v ... = ... unsafeWrite mv i (unsafeIndex v i) ...
-  --
-  -- For lazy vectors, the indexing would not be evaluated which means that we
-  -- would retain a reference to the original vector in each element we write.
-  -- This is not what we want!
-  --
-  -- With 'unsafeIndexM', we can do
-  --
-  -- > copy mv v ... = ... case unsafeIndexM v i of
-  -- >                       Box x -> unsafeWrite mv i x ...
-  --
-  -- which does not have this problem because indexing (but not the returned
-  -- element!) is evaluated immediately.
-  --
-  unsafeIndexM  :: Monad m => v a -> Int -> m a
-
--- Fusion
--- ------
-
--- | Construct a pure vector from a monadic initialiser 
-new :: IVector v a => New a -> v a
-{-# INLINE new #-}
-new m = new' undefined m
-
--- | Same as 'new' but with a dummy argument necessary for correctly typing
--- the rule @uninplace@.
---
--- See http://hackage.haskell.org/trac/ghc/ticket/2600
-new' :: IVector v a => v a -> New a -> v a
-{-# INLINE_STREAM new' #-}
-new' _ m = vnew (New.run m)
-
--- | Convert a vector to a 'Stream'
-stream :: IVector v a => v a -> Stream a
-{-# INLINE_STREAM stream #-}
-stream v = v `seq` (Stream.unfoldr get 0 `Stream.sized` Exact n)
-  where
-    n = length v
-
-    {-# INLINE get #-}
-    get i | i < n     = case unsafeIndexM v i of Box x -> Just (x, i+1)
-          | otherwise = Nothing
-
--- | Create a vector from a 'Stream'
-unstream :: IVector v a => Stream a -> v a
-{-# INLINE unstream #-}
-unstream s = new (New.unstream s)
-
-{-# RULES
-
-"stream/unstream [IVector]" forall v s.
-  stream (new' v (New.unstream s)) = s
-
-"New.unstream/stream/new [IVector]" forall v p.
-  New.unstream (stream (new' v p)) = p
-
- #-}
-
-inplace :: (forall m. Monad m => MStream m a -> MStream m a)
-        -> Stream a -> Stream a
-{-# INLINE_STREAM inplace #-}
-inplace f s = f s
-
-{-# RULES
-
-"inplace [IVector]"
-  forall (f :: forall m. Monad m => MStream m a -> MStream m a) v m.
-  New.unstream (inplace f (stream (new' v m))) = New.transform f m
-
-"uninplace [IVector]"
-  forall (f :: forall m. Monad m => MStream m a -> MStream m a) v m.
-  stream (new' v (New.transform f m)) = inplace f (stream (new' v m))
-
-"inplace/inplace [IVector]"
-  forall (f :: forall m. Monad m => MStream m a -> MStream m a)
-         (g :: forall m. Monad m => MStream m a -> MStream m a)
-         s.
-  inplace f (inplace g s) = inplace (f . g) s
-
- #-}
-
--- Length
--- ------
-
-length :: IVector v a => v a -> Int
-{-# INLINE_STREAM length #-}
-length v = vlength v
-
-{-# RULES
-
-"length/unstream [IVector]" forall v s.
-  length (new' v (New.unstream s)) = Stream.length s
-
-  #-}
-
-null :: IVector v a => v a -> Bool
-{-# INLINE_STREAM null #-}
-null v = vlength v == 0
-
-{-# RULES
-
-"null/unstream [IVector]" forall v s.
-  null (new' v (New.unstream s)) = Stream.null s
-
-  #-}
-
--- Construction
--- ------------
-
--- | Empty vector
-empty :: IVector v a => v a
-{-# INLINE empty #-}
-empty = unstream Stream.empty
-
--- | Vector with exaclty one element
-singleton :: IVector v a => a -> v a
-{-# INLINE singleton #-}
-singleton x = unstream (Stream.singleton x)
-
--- | Vector of the given length with the given value in each position
-replicate :: IVector v a => Int -> a -> v a
-{-# INLINE replicate #-}
-replicate n = unstream . Stream.replicate n
-
--- | Prepend an element
-cons :: IVector v a => a -> v a -> v a
-{-# INLINE cons #-}
-cons x = unstream . Stream.cons x . stream
-
--- | Append an element
-snoc :: IVector v a => v a -> a -> v a
-{-# INLINE snoc #-}
-snoc v = unstream . Stream.snoc (stream v)
-
-infixr 5 ++
--- | Concatenate two vectors
-(++) :: IVector v a => v a -> v a -> v a
-{-# INLINE (++) #-}
-v ++ w = unstream (stream v Stream.++ stream w)
-
--- | Create a copy of a vector. Useful when dealing with slices.
-copy :: IVector v a => v a -> v a
-{-# INLINE_STREAM copy #-}
-copy = unstream . stream
-
-{-# RULES
-
-"copy/unstream [IVector]" forall v s.
-  copy (new' v (New.unstream s)) = new' v (New.unstream s)
-
- #-}
-
--- Accessing individual elements
--- -----------------------------
-
--- | Indexing
-(!) :: IVector v a => v a -> Int -> a
-{-# INLINE_STREAM (!) #-}
-v ! i = assert (i >= 0 && i < length v)
-      $ unId (unsafeIndexM v i)
-
--- | First element
-head :: IVector v a => v a -> a
-{-# INLINE_STREAM head #-}
-head v = v ! 0
-
--- | Last element
-last :: IVector v a => v a -> a
-{-# INLINE_STREAM last #-}
-last v = v ! (length v - 1)
-
-{-# RULES
-
-"(!)/unstream [IVector]" forall v i s.
-  new' v (New.unstream s) ! i = s Stream.!! i
-
-"head/unstream [IVector]" forall v s.
-  head (new' v (New.unstream s)) = Stream.head s
-
-"last/unstream [IVector]" forall v s.
-  last (new' v (New.unstream s)) = Stream.last s
-
- #-}
-
--- | Monadic indexing which can be strict in the vector while remaining lazy in
--- the element.
-indexM :: (IVector v a, Monad m) => v a -> Int -> m a
-{-# INLINE_STREAM indexM #-}
-indexM v i = assert (i >= 0 && i < length v)
-           $ unsafeIndexM v i
-
-headM :: (IVector v a, Monad m) => v a -> m a
-{-# INLINE_STREAM headM #-}
-headM v = indexM v 0
-
-lastM :: (IVector v a, Monad m) => v a -> m a
-{-# INLINE_STREAM lastM #-}
-lastM v = indexM v (length v - 1)
-
-{-# RULES
-
-"indexM/unstream [IVector]" forall v i s.
-  indexM (new' v (New.unstream s)) i = return (s Stream.!! i)
-
-"headM/unstream [IVector]" forall v s.
-  headM (new' v (New.unstream s)) = return (Stream.head s)
-
-"lastM/unstream [IVector]" forall v s.
-  lastM (new' v (New.unstream s)) = return (Stream.last s)
-
- #-}
-
--- Subarrays
--- ---------
-
--- FIXME: slicing doesn't work with the inplace stuff at the moment
-
--- | Yield a part of the vector without copying it. Safer version of
--- 'unsafeSlice'.
-slice :: IVector v a => v a -> Int   -- ^ starting index
-                            -> Int   -- ^ length
-                            -> v a
-{-# INLINE_STREAM slice #-}
-slice v i n = assert (i >= 0 && n >= 0  && i+n <= length v)
-            $ unsafeSlice v i n
-
--- | Yield all but the last element without copying.
-init :: IVector v a => v a -> v a
-{-# INLINE_STREAM init #-}
-init v = slice v 0 (length v - 1)
-
--- | All but the first element (without copying).
-tail :: IVector v a => v a -> v a
-{-# INLINE_STREAM tail #-}
-tail v = slice v 1 (length v - 1)
-
--- | Yield the first @n@ elements without copying.
-take :: IVector v a => Int -> v a -> v a
-{-# INLINE_STREAM take #-}
-take n v = slice v 0 (min n' (length v))
-  where n' = max n 0
-
--- | Yield all but the first @n@ elements without copying.
-drop :: IVector v a => Int -> v a -> v a
-{-# INLINE_STREAM drop #-}
-drop n v = slice v (min n' len) (max 0 (len - n'))
-  where n' = max n 0
-        len = length v
-
-{-# RULES
-
-"slice/new [IVector]" forall v p i n.
-  slice (new' v p) i n = new' v (New.slice p i n)
-
-"init/new [IVector]" forall v p.
-  init (new' v p) = new' v (New.init p)
-
-"tail/new [IVector]" forall v p.
-  tail (new' v p) = new' v (New.tail p)
-
-"take/new [IVector]" forall n v p.
-  take n (new' v p) = new' v (New.take n p)
-
-"drop/new [IVector]" forall n v p.
-  drop n (new' v p) = new' v (New.drop n p)
-
-  #-}
-
--- Permutations
--- ------------
-
-accum :: IVector v a => (a -> b -> a) -> v a -> [(Int,b)] -> v a
-{-# INLINE accum #-}
-accum f v us = new (New.accum f (New.unstream (stream v))
-                                (Stream.fromList us))
-
-(//) :: IVector v a => v a -> [(Int, a)] -> v a
-{-# INLINE (//) #-}
-v // us = new (New.update (New.unstream (stream v))
-                          (Stream.fromList us))
-
-update :: (IVector v a, IVector v (Int, a)) => v a -> v (Int, a) -> v a
-{-# INLINE update #-}
-update v w = new (New.update (New.unstream (stream v)) (stream w))
-
--- This somewhat non-intuitive definition ensures that the resulting vector
--- does not retain references to the original one even if it is lazy in its
--- elements. This would not be the case if we simply used
---
--- backpermute v is = map (v!) is
-backpermute :: (IVector v a, IVector v Int) => v a -> v Int -> v a
-{-# INLINE backpermute #-}
-backpermute v is = unstream
-                 . MStream.trans (Id . unBox)
-                 . MStream.mapM (indexM v)
-                 . MStream.trans (Box . unId)
-                 $ stream is
-
-reverse :: (IVector v a) => v a -> v a
-{-# INLINE reverse #-}
-reverse = new . New.reverse . New.unstream . stream
-
--- Mapping
--- -------
-
--- | Map a function over a vector
-map :: (IVector v a, IVector v b) => (a -> b) -> v a -> v b
-{-# INLINE map #-}
-map f = unstream . Stream.map f . stream
-
-inplace_map :: IVector v a => (a -> a) -> v a -> v a
-{-# INLINE inplace_map #-}
-inplace_map f = unstream . inplace (MStream.map f) . stream
-
-{-# RULES
-
-"map->inplace_map [IVector]" map = inplace_map
-
- #-}
-
-concatMap :: (IVector v a, IVector v b) => (a -> v b) -> v a -> v b
-{-# INLINE concatMap #-}
-concatMap f = unstream . Stream.concatMap (stream . f) . stream
-
--- Zipping/unzipping
--- -----------------
-
--- | Zip two vectors with the given function.
-zipWith :: (IVector v a, IVector v b, IVector v c) => (a -> b -> c) -> v a -> v b -> v c
-{-# INLINE zipWith #-}
-zipWith f xs ys = unstream (Stream.zipWith f (stream xs) (stream ys))
-
--- | Zip three vectors with the given function.
-zipWith3 :: (IVector v a, IVector v b, IVector v c, IVector v d) => (a -> b -> c -> d) -> v a -> v b -> v c -> v d
-{-# INLINE zipWith3 #-}
-zipWith3 f xs ys zs = unstream (Stream.zipWith3 f (stream xs) (stream ys) (stream zs))
-
-zip :: (IVector v a, IVector v b, IVector v (a,b)) => v a -> v b -> v (a, b)
-{-# INLINE zip #-}
-zip = zipWith (,)
-
-zip3 :: (IVector v a, IVector v b, IVector v c, IVector v (a, b, c)) => v a -> v b -> v c -> v (a, b, c)
-{-# INLINE zip3 #-}
-zip3 = zipWith3 (,,)
-
-unzip :: (IVector v a, IVector v b, IVector v (a,b)) => v (a, b) -> (v a, v b)
-{-# INLINE unzip #-}
-unzip xs = (map fst xs, map snd xs)
-
-unzip3 :: (IVector v a, IVector v b, IVector v c, IVector v (a, b, c)) => v (a, b, c) -> (v a, v b, v c)
-{-# INLINE unzip3 #-}
-unzip3 xs = (map (\(a, b, c) -> a) xs, map (\(a, b, c) -> b) xs, map (\(a, b, c) -> c) xs)
-
--- Comparisons
--- -----------
-
-eq :: (IVector v a, Eq a) => v a -> v a -> Bool
-{-# INLINE eq #-}
-xs `eq` ys = stream xs == stream ys
-
-cmp :: (IVector v a, Ord a) => v a -> v a -> Ordering
-{-# INLINE cmp #-}
-cmp xs ys = compare (stream xs) (stream ys)
-
--- Filtering
--- ---------
-
--- | Drop elements which do not satisfy the predicate
-filter :: IVector v a => (a -> Bool) -> v a -> v a
-{-# INLINE filter #-}
-filter f = unstream . inplace (MStream.filter f) . stream
-
--- | Yield the longest prefix of elements satisfying the predicate.
-takeWhile :: IVector v a => (a -> Bool) -> v a -> v a
-{-# INLINE takeWhile #-}
-takeWhile f = unstream . Stream.takeWhile f . stream
-
--- | Drop the longest prefix of elements that satisfy the predicate.
-dropWhile :: IVector v a => (a -> Bool) -> v a -> v a
-{-# INLINE dropWhile #-}
-dropWhile f = unstream . Stream.dropWhile f . stream
-
--- Searching
--- ---------
-
-infix 4 `elem`
--- | Check whether the vector contains an element
-elem :: (IVector v a, Eq a) => a -> v a -> Bool
-{-# INLINE elem #-}
-elem x = Stream.elem x . stream
-
-infix 4 `notElem`
--- | Inverse of `elem`
-notElem :: (IVector v a, Eq a) => a -> v a -> Bool
-{-# INLINE notElem #-}
-notElem x = Stream.notElem x . stream
-
--- | Yield 'Just' the first element matching the predicate or 'Nothing' if no
--- such element exists.
-find :: IVector v a => (a -> Bool) -> v a -> Maybe a
-{-# INLINE find #-}
-find f = Stream.find f . stream
-
--- | Yield 'Just' the index of the first element matching the predicate or
--- 'Nothing' if no such element exists.
-findIndex :: IVector v a => (a -> Bool) -> v a -> Maybe Int
-{-# INLINE findIndex #-}
-findIndex f = Stream.findIndex f . stream
-
--- Folding
--- -------
-
--- | Left fold
-foldl :: IVector v b => (a -> b -> a) -> a -> v b -> a
-{-# INLINE foldl #-}
-foldl f z = Stream.foldl f z . stream
-
--- | Lefgt fold on non-empty vectors
-foldl1 :: IVector v a => (a -> a -> a) -> v a -> a
-{-# INLINE foldl1 #-}
-foldl1 f = Stream.foldl1 f . stream
-
--- | Left fold with strict accumulator
-foldl' :: IVector v b => (a -> b -> a) -> a -> v b -> a
-{-# INLINE foldl' #-}
-foldl' f z = Stream.foldl' f z . stream
-
--- | Left fold on non-empty vectors with strict accumulator
-foldl1' :: IVector v a => (a -> a -> a) -> v a -> a
-{-# INLINE foldl1' #-}
-foldl1' f = Stream.foldl1' f . stream
-
--- | Right fold
-foldr :: IVector v a => (a -> b -> b) -> b -> v a -> b
-{-# INLINE foldr #-}
-foldr f z = Stream.foldr f z . stream
-
--- | Right fold on non-empty vectors
-foldr1 :: IVector v a => (a -> a -> a) -> v a -> a
-{-# INLINE foldr1 #-}
-foldr1 f = Stream.foldr1 f . stream
-
--- Specialised folds
--- -----------------
-
-and :: IVector v Bool => v Bool -> Bool
-{-# INLINE and #-}
-and = Stream.and . stream
-
-or :: IVector v Bool => v Bool -> Bool
-{-# INLINE or #-}
-or = Stream.or . stream
-
-sum :: (IVector v a, Num a) => v a -> a
-{-# INLINE sum #-}
-sum = Stream.foldl' (+) 0 . stream
-
-product :: (IVector v a, Num a) => v a -> a
-{-# INLINE product #-}
-product = Stream.foldl' (*) 1 . stream
-
-maximum :: (IVector v a, Ord a) => v a -> a
-{-# INLINE maximum #-}
-maximum = Stream.foldl1' max . stream
-
-minimum :: (IVector v a, Ord a) => v a -> a
-{-# INLINE minimum #-}
-minimum = Stream.foldl1' min . stream
-
--- Unfolding
--- ---------
-
-unfoldr :: IVector v a => (b -> Maybe (a, b)) -> b -> v a
-{-# INLINE unfoldr #-}
-unfoldr f = unstream . Stream.unfoldr f
-
--- Scans
--- -----
-
--- | Prefix scan
-prescanl :: (IVector v a, IVector v b) => (a -> b -> a) -> a -> v b -> v a
-{-# INLINE prescanl #-}
-prescanl f z = unstream . Stream.prescanl f z . stream
-
-inplace_prescanl :: IVector v a => (a -> a -> a) -> a -> v a -> v a
-{-# INLINE inplace_prescanl #-}
-inplace_prescanl f z = unstream . inplace (MStream.prescanl f z) . stream
-
-{-# RULES
-
-"prescanl -> inplace_prescanl [IVector]" prescanl = inplace_prescanl
-
- #-}
-
--- | Prefix scan with strict accumulator
-prescanl' :: (IVector v a, IVector v b) => (a -> b -> a) -> a -> v b -> v a
-{-# INLINE prescanl' #-}
-prescanl' f z = unstream . Stream.prescanl' f z . stream
-
-inplace_prescanl' :: IVector v a => (a -> a -> a) -> a -> v a -> v a
-{-# INLINE inplace_prescanl' #-}
-inplace_prescanl' f z = unstream . inplace (MStream.prescanl' f z) . stream
-
-{-# RULES
-
-"prescanl' -> inplace_prescanl' [IVector]" prescanl' = inplace_prescanl'
-
- #-}
-
-
--- Enumeration
--- -----------
-
-enumFromTo :: (IVector v a, Enum a) => a -> a -> v a
-{-# INLINE enumFromTo #-}
-enumFromTo from to = from `seq` to `seq` unfoldr enumFromTo_go (fromEnum from)
-  where
-    to_i = fromEnum to
-    enumFromTo_go i | i <= to_i = Just (toEnum i, i + 1)
-                    | otherwise = Nothing
-
-enumFromThenTo :: (IVector v a, Enum a) => a -> a -> a -> v a
-{-# INLINE enumFromThenTo #-}
-enumFromThenTo from next to = from `seq` next `seq` to `seq` unfoldr enumFromThenTo_go from_i
-  where
-    from_i = fromEnum from
-    to_i = fromEnum to
-    step_i = fromEnum next - from_i
-    enumFromThenTo_go i | i <= to_i = Just (toEnum i, i + step_i)
-                        | otherwise = Nothing
-
--- | Convert a vector to a list
-toList :: IVector v a => v a -> [a]
-{-# INLINE toList #-}
-toList = Stream.toList . stream
-
--- | Convert a list to a vector
-fromList :: IVector v a => [a] -> v a
-{-# INLINE fromList #-}
-fromList = unstream . Stream.fromList
-
diff --git a/Data/Vector/MVector.hs b/Data/Vector/MVector.hs
deleted file mode 100644
--- a/Data/Vector/MVector.hs
+++ /dev/null
@@ -1,256 +0,0 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
--- |
--- Module      : Data.Vector.MVector
--- Copyright   : (c) Roman Leshchinskiy 2008
--- License     : BSD-style
---
--- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
--- Stability   : experimental
--- Portability : non-portable
--- 
--- Generic interface to mutable vectors
---
-
-#include "phases.h"
-
-module Data.Vector.MVector (
-  MVectorPure(..), MVector(..),
-
-  slice, new, newWith, read, write, copy, grow,
-  unstream, transform,
-  accum, update, reverse
-) where
-
-import qualified Data.Vector.Fusion.Stream      as Stream
-import           Data.Vector.Fusion.Stream      ( Stream, MStream )
-import qualified Data.Vector.Fusion.Stream.Monadic as MStream
-import           Data.Vector.Fusion.Stream.Size
-
-import Control.Monad.ST ( ST )
-import Control.Exception ( assert )
-
-import GHC.Float (
-    double2Int, int2Double
-  )
-
-import Prelude hiding ( length, reverse, map, read )
-
-gROWTH_FACTOR :: Double
-gROWTH_FACTOR = 1.5
-
--- | Basic pure functions on mutable vectors
-class MVectorPure v a where
-  -- | Length of the mutable vector
-  length           :: v a -> Int
-
-  -- | Yield a part of the mutable vector without copying it. No range checks!
-  unsafeSlice      :: v a -> Int  -- ^ starting index
-                          -> Int  -- ^ length of the slice
-                          -> v a
-
-  -- Check whether two vectors overlap.
-  overlaps         :: v a -> v a -> Bool
-
--- | Class of mutable vectors. The type @m@ is the monad in which the mutable
--- vector can be transformed and @a@ is the type of elements.
---
-class (Monad m, MVectorPure v a) => MVector v m a where
-  -- | Create a mutable vector of the given length. Length is not checked!
-  unsafeNew        :: Int -> m (v a)
-
-  -- | Create a mutable vector of the given length and fill it with an
-  -- initial value. Length is not checked!
-  unsafeNewWith    :: Int -> a -> m (v a)
-
-  -- | Yield the element at the given position. Index is not checked!
-  unsafeRead       :: v a -> Int -> m a
-
-  -- | Replace the element at the given position. Index is not checked!
-  unsafeWrite      :: v a -> Int -> a -> m ()
-
-  -- | Clear all references to external objects
-  clear            :: v a -> m ()
-
-  -- | Write the value at each position.
-  set              :: v a -> a -> m ()
-
-  -- | Copy a vector. The two vectors may not overlap. This is not checked!
-  unsafeCopy       :: v a   -- ^ target
-                   -> v a   -- ^ source
-                   -> m ()
-
-  -- | Grow a vector by the given number of elements. The length is not
-  -- checked!
-  unsafeGrow       :: v a -> Int -> m (v a)
-
-  {-# INLINE unsafeNewWith #-}
-  unsafeNewWith n x = do
-                        v <- unsafeNew n
-                        set v x
-                        return v
-
-  {-# INLINE set #-}
-  set v x = do_set 0
-    where
-      n = length v
-
-      do_set i | i < n = do
-                            unsafeWrite v i x
-                            do_set (i+1)
-                | otherwise = return ()
-
-  {-# INLINE unsafeCopy #-}
-  unsafeCopy dst src = do_copy 0
-    where
-      n = length src
-
-      do_copy i | i < n = do
-                            x <- unsafeRead src i
-                            unsafeWrite dst i x
-                            do_copy (i+1)
-                | otherwise = return ()
-
-  {-# INLINE unsafeGrow #-}
-  unsafeGrow v by = do
-                      v' <- unsafeNew (n+by)
-                      unsafeCopy (unsafeSlice v' 0 n) v
-                      return v'
-    where
-      n = length v
-
--- | Test whether the index is valid for the vector
-inBounds :: MVectorPure v a => v a -> Int -> Bool
-{-# INLINE inBounds #-}
-inBounds v i = i >= 0 && i < length v
-
--- | Yield a part of the mutable vector without copying it. Safer version of
--- 'unsafeSlice'.
-slice :: MVectorPure v a => v a -> Int -> Int -> v a
-{-# INLINE slice #-}
-slice v i n = assert (i >=0 && n >= 0 && i+n <= length v)
-            $ unsafeSlice v i n
-
--- | Create a mutable vector of the given length. Safer version of
--- 'unsafeNew'.
-new :: MVector v m a => Int -> m (v a)
-{-# INLINE new #-}
-new n = assert (n >= 0) $ unsafeNew n
-
--- | Create a mutable vector of the given length and fill it with an
--- initial value. Safer version of 'unsafeNewWith'.
-newWith :: MVector v m a => Int -> a -> m (v a)
-{-# INLINE newWith #-}
-newWith n x = assert (n >= 0) $ unsafeNewWith n x
-
--- | Yield the element at the given position. Safer version of 'unsafeRead'.
-read :: MVector v m a => v a -> Int -> m a
-{-# INLINE read #-}
-read v i = assert (inBounds v i) $ unsafeRead v i
-
--- | Replace the element at the given position. Safer version of
--- 'unsafeWrite'.
-write :: MVector v m a => v a -> Int -> a -> m ()
-{-# INLINE write #-}
-write v i x = assert (inBounds v i) $ unsafeWrite v i x
-
--- | Copy a vector. The two vectors may not overlap. Safer version of
--- 'unsafeCopy'.
-copy :: MVector v m a => v a -> v a -> m ()
-{-# INLINE copy #-}
-copy dst src = assert (not (dst `overlaps` src) && length dst == length src)
-             $ unsafeCopy dst src
-
--- | Grow a vector by the given number of elements. Safer version of
--- 'unsafeGrow'.
-grow :: MVector v m a => v a -> Int -> m (v a)
-{-# INLINE grow #-}
-grow v by = assert (by >= 0)
-          $ unsafeGrow v by
-
-mstream :: MVector v m a => v a -> MStream m a
-{-# INLINE mstream #-}
-mstream v = v `seq` (MStream.unfoldrM get 0 `MStream.sized` Exact n)
-  where
-    n = length v
-
-    {-# INLINE get #-}
-    get i | i < n     = do x <- unsafeRead v i
-                           return $ Just (x, i+1)
-          | otherwise = return $ Nothing
-
-munstream :: MVector v m a => v a -> MStream m a -> m (v a)
-{-# INLINE munstream #-}
-munstream v s = v `seq` do
-                          n' <- MStream.foldM put 0 s
-                          return $ slice v 0 n'
-  where
-    put i x = do { write v i x; return (i+1) }
-
-transform :: MVector v m a => (MStream m a -> MStream m a) -> v a -> m (v a)
-{-# INLINE_STREAM transform #-}
-transform f v = munstream v (f (mstream v))
-
--- | Create a new mutable vector and fill it with elements from the 'Stream'.
--- The vector will grow logarithmically if the 'Size' hint of the 'Stream' is
--- inexact.
-unstream :: MVector v m a => Stream a -> m (v a)
-{-# INLINE_STREAM unstream #-}
-unstream s = case upperBound (Stream.size s) of
-               Just n  -> unstreamMax     s n
-               Nothing -> unstreamUnknown s
-
-unstreamMax :: MVector v m a => Stream a -> Int -> m (v a)
-{-# INLINE unstreamMax #-}
-unstreamMax s n
-  = do
-      v  <- new n
-      let put i x = do { write v i x; return (i+1) }
-      n' <- Stream.foldM put 0 s
-      return $ slice v 0 n'
-
-unstreamUnknown :: MVector v m a => Stream a -> m (v a)
-{-# INLINE unstreamUnknown #-}
-unstreamUnknown s
-  = do
-      v <- new 0
-      (v', n) <- Stream.foldM put (v, 0) s
-      return $ slice v' 0 n
-  where
-    {-# INLINE put #-}
-    put (v, i) x = do
-                     v' <- enlarge v i
-                     unsafeWrite v' i x
-                     return (v', i+1)
-
-    {-# INLINE enlarge #-}
-    enlarge v i | i < length v = return v
-                | otherwise    = unsafeGrow v
-                                 . max 1
-                                 . double2Int
-                                 $ int2Double (length v) * gROWTH_FACTOR
-
-accum :: MVector v m a => (a -> b -> a) -> v a -> Stream (Int, b) -> m ()
-{-# INLINE accum #-}
-accum f v s = Stream.mapM_ upd s
-  where
-    {-# INLINE upd #-}
-    upd (i,b) = do
-                  a <- read v i
-                  write v i (f a b)
-
-update :: MVector v m a => v a -> Stream (Int, a) -> m ()
-{-# INLINE update #-}
-update = accum (const id)
-
-reverse :: MVector v m a => v a -> m ()
-{-# INLINE reverse #-}
-reverse v = reverse_loop 0 (length v - 1)
-  where
-    reverse_loop i j | i < j = do
-                                 x <- unsafeRead v i
-                                 y <- unsafeRead v j
-                                 unsafeWrite v i y
-                                 unsafeWrite v j x
-                                 reverse_loop (i + 1) (j - 1)
-    reverse_loop _ _ = return ()
-
diff --git a/Data/Vector/MVector/New.hs b/Data/Vector/MVector/New.hs
deleted file mode 100644
--- a/Data/Vector/MVector/New.hs
+++ /dev/null
@@ -1,108 +0,0 @@
-{-# LANGUAGE Rank2Types, ScopedTypeVariables #-}
-
-#include "phases.h"
-
-module Data.Vector.MVector.New (
-  New(..), run, unstream, transform, accum, update, reverse,
-  slice, init, tail, take, drop
-) where
-
-import qualified Data.Vector.MVector as MVector
-import           Data.Vector.MVector ( MVector, MVectorPure )
-
-import           Data.Vector.Fusion.Stream ( Stream, MStream )
-import qualified Data.Vector.Fusion.Stream as Stream
-
-import qualified Data.Vector.Fusion.Stream.Monadic as MStream
-
-import Control.Monad  ( liftM )
-import Prelude hiding ( init, tail, take, drop, reverse, map, filter )
-
-newtype New a = New (forall m mv. MVector mv m a => m (mv a))
-
-run :: MVector mv m a => New a -> m (mv a)
-{-# INLINE run #-}
-run (New p) = p
-
-apply :: (forall mv a. MVectorPure mv a => mv a -> mv a) -> New a -> New a
-{-# INLINE apply #-}
-apply f (New p) = New (liftM f p)
-
-modify :: New a -> (forall m mv. MVector mv m a => mv a -> m ()) -> New a
-{-# INLINE modify #-}
-modify (New p) q = New (do { v <- p; q v; return v })
-
-unstream :: Stream a -> New a
-{-# INLINE_STREAM unstream #-}
-unstream s = New (MVector.unstream s)
-
-transform :: (forall m. Monad m => MStream m a -> MStream m a) -> New a -> New a
-{-# INLINE_STREAM transform #-}
-transform f (New p) = New (MVector.transform f =<< p)
-
-{-# RULES
-
-"transform/transform [New]"
-  forall (f :: forall m. Monad m => MStream m a -> MStream m a)
-         (g :: forall m. Monad m => MStream m a -> MStream m a)
-         p .
-  transform f (transform g p) = transform (f . g) p
-
-"transform/unstream [New]"
-  forall (f :: forall m. Monad m => MStream m a -> MStream m a)
-         s.
-  transform f (unstream s) = unstream (f s)
-
- #-}
-
-slice :: New a -> Int -> Int -> New a
-{-# INLINE_STREAM slice #-}
-slice m i n = apply (\v -> MVector.slice v i n) m
-
-init :: New a -> New a
-{-# INLINE_STREAM init #-}
-init m = apply (\v -> MVector.slice v 0 (MVector.length v - 1)) m
-
-tail :: New a -> New a
-{-# INLINE_STREAM tail #-}
-tail m = apply (\v -> MVector.slice v 1 (MVector.length v - 1)) m
-
-take :: Int -> New a -> New a
-{-# INLINE_STREAM take #-}
-take n m = apply (\v -> MVector.slice v 0 (min n (MVector.length v))) m
-
-drop :: Int -> New a -> New a
-{-# INLINE_STREAM drop #-}
-drop n m = apply (\v -> MVector.slice v n (max 0 (MVector.length v - n))) m
-
-{-# RULES
-
-"slice/unstream [New]" forall s i n.
-  slice (unstream s) i n = unstream (Stream.extract s i n)
-
-"init/unstream [New]" forall s.
-  init (unstream s) = unstream (Stream.init s)
-
-"tail/unstream [New]" forall s.
-  tail (unstream s) = unstream (Stream.tail s)
-
-"take/unstream [New]" forall n s.
-  take n (unstream s) = unstream (Stream.take n s)
-
-"drop/unstream [New]" forall n s.
-  drop n (unstream s) = unstream (Stream.drop n s)
-
-  #-}
-
-accum :: (a -> b -> a) -> New a -> Stream (Int, b) -> New a
-{-# INLINE_STREAM accum #-}
-accum f m s = modify m (\v -> MVector.accum f v s)
-
-update :: New a -> Stream (Int, a) -> New a
-{-# INLINE_STREAM update #-}
-update m s = modify m (\v -> MVector.update v s)
-
-reverse :: New a -> New a
-{-# INLINE_STREAM reverse #-}
-reverse m = modify m (MVector.reverse)
-
diff --git a/Data/Vector/Mutable.hs b/Data/Vector/Mutable.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Mutable.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
+
+-- |
+-- Module      : Data.Vector.Mutable
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- Mutable boxed vectors.
+--
+
+module Data.Vector.Mutable ( MVector(..), IOVector, STVector )
+where
+
+import qualified Data.Vector.Generic.Mutable as G
+import           Data.Primitive.Array
+import           Control.Monad.Primitive ( PrimMonad )
+import           Control.Monad.ST ( ST )
+
+-- | Mutable boxed vectors keyed on the monad they live in ('IO' or @'ST' s@).
+data MVector m a = MVector {-# UNPACK #-} !Int
+                           {-# UNPACK #-} !Int
+                           {-# UNPACK #-} !(MutableArray m a)
+
+type IOVector = MVector IO
+type STVector s = MVector (ST s)
+
+instance G.MVectorPure (MVector m) a where
+  length (MVector _ n _) = n
+  unsafeSlice (MVector i _ arr) j m = MVector (i+j) m arr
+
+  {-# INLINE overlaps #-}
+  overlaps (MVector i m arr1) (MVector j n arr2)
+    = sameMutableArray arr1 arr2
+      && (between i j (j+n) || between j i (i+m))
+    where
+      between x y z = x >= y && x < z
+
+
+instance PrimMonad m => G.MVector (MVector m) m a where
+  {-# INLINE unsafeNew #-}
+  unsafeNew n = do
+                  arr <- newArray n uninitialised
+                  return (MVector 0 n arr)
+
+  {-# INLINE unsafeNewWith #-}
+  unsafeNewWith n x = do
+                        arr <- newArray n x
+                        return (MVector 0 n arr)
+
+  {-# INLINE unsafeRead #-}
+  unsafeRead (MVector i _ arr) j = readArray arr (i+j)
+
+  {-# INLINE unsafeWrite #-}
+  unsafeWrite (MVector i _ arr) j x = writeArray arr (i+j) x
+
+  {-# INLINE clear #-}
+  clear v = G.set v uninitialised
+
+uninitialised :: a
+uninitialised = error "Data.Vector.Mutable: uninitialised element"
+
diff --git a/Data/Vector/Mutable/IO.hs b/Data/Vector/Mutable/IO.hs
deleted file mode 100644
--- a/Data/Vector/Mutable/IO.hs
+++ /dev/null
@@ -1,58 +0,0 @@
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
-
--- |
--- Module      : Data.Vector.Mutable.IO
--- Copyright   : (c) Roman Leshchinskiy 2009
--- License     : BSD-style
---
--- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
--- Stability   : experimental
--- Portability : non-portable
--- 
--- Mutable boxed vectors in the IO monad.
---
-
-module Data.Vector.Mutable.IO ( Vector(..) )
-where
-
-import           Data.Vector.MVector ( MVector(..), MVectorPure(..) )
-import qualified Data.Vector.Mutable.ST as STV
-
-import GHC.Base   ( RealWorld )
-import GHC.ST     ( ST(..) )
-import GHC.IOBase ( IO(..) )
-
-import Prelude hiding ( length )
-
--- | IO-based mutable vectors
-newtype Vector a = Vector (STV.Vector RealWorld a)
-
-instance MVectorPure Vector a where
-  {-# INLINE length #-}
-  length (Vector v) = length v
-
-  {-# INLINE unsafeSlice #-}
-  unsafeSlice (Vector v) j m = Vector (unsafeSlice v j m)
-
-  {-# INLINE overlaps #-}
-  overlaps (Vector v1) (Vector v2) = overlaps v1 v2
-
-instance MVector Vector IO a where
-  {-# INLINE unsafeNew #-}
-  unsafeNew n = Vector `fmap` stToIO (unsafeNew n)
-
-  {-# INLINE unsafeNewWith #-}
-  unsafeNewWith n x = Vector `fmap` stToIO (unsafeNewWith n x)
-
-  {-# INLINE unsafeRead #-}
-  unsafeRead (Vector v) i = stToIO (unsafeRead v i)
-
-  {-# INLINE unsafeWrite #-}
-  unsafeWrite (Vector v) i x = stToIO (unsafeWrite v i x)
-
-  {-# INLINE clear #-}
-  clear (Vector v) = stToIO (clear v)
-
-stToIO :: ST RealWorld a -> IO a
-stToIO (ST m) = IO m
-
diff --git a/Data/Vector/Mutable/ST.hs b/Data/Vector/Mutable/ST.hs
deleted file mode 100644
--- a/Data/Vector/Mutable/ST.hs
+++ /dev/null
@@ -1,77 +0,0 @@
-{-# LANGUAGE MagicHash, UnboxedTuples, MultiParamTypeClasses, FlexibleInstances #-}
-
--- |
--- Module      : Data.Vector.Mutable.ST
--- Copyright   : (c) Roman Leshchinskiy 2008
--- License     : BSD-style
---
--- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
--- Stability   : experimental
--- Portability : non-portable
--- 
--- Mutable boxed vectors in the ST monad.
---
-
-module Data.Vector.Mutable.ST ( Vector(..) )
-where
-
-import qualified Data.Vector.MVector as MVector
-import           Data.Vector.MVector ( MVector, MVectorPure )
-
-import GHC.Prim ( MutableArray#,
-                  newArray#, readArray#, writeArray#, sameMutableArray#, (+#) )
-
-import GHC.ST   ( ST(..) )
-
-import GHC.Base ( Int(..) )
-
--- | Mutable boxed vectors. They live in the 'ST' monad.
-data Vector s a = Vector {-# UNPACK #-} !Int
-                         {-# UNPACK #-} !Int
-                                        (MutableArray# s a)
-
-instance MVectorPure (Vector s) a where
-  length (Vector _ n _) = n
-  unsafeSlice (Vector i _ arr#) j m = Vector (i+j) m arr#
-
-  {-# INLINE overlaps #-}
-  overlaps (Vector i m arr1#) (Vector j n arr2#)
-    = sameMutableArray# arr1# arr2#
-      && (between i j (j+n) || between j i (i+m))
-    where
-      between x y z = x >= y && x < z
-
-
-instance MVector (Vector s) (ST s) a where
-  {-# INLINE unsafeNew #-}
-  unsafeNew = unsafeNew
-
-  {-# INLINE unsafeNewWith #-}
-  unsafeNewWith = unsafeNewWith
-
-  {-# INLINE unsafeRead #-}
-  unsafeRead (Vector (I# i#) _ arr#) (I# j#) = ST (readArray# arr# (i# +# j#))
-
-  {-# INLINE unsafeWrite #-}
-  unsafeWrite (Vector (I# i#) _ arr#) (I# j#) x = ST (\s# ->
-      case writeArray# arr# (i# +# j#) x s# of s2# -> (# s2#, () #)
-    )
-
-  {-# INLINE clear #-}
-  clear v = MVector.set v uninitialised
-
-
-uninitialised :: a
-uninitialised = error "Data.Vector.Mutable: uninitialised elemen t"
-
-unsafeNew :: Int -> ST s (Vector s a)
-{-# INLINE unsafeNew #-}
-unsafeNew n = unsafeNewWith n uninitialised
-
-unsafeNewWith :: Int -> a -> ST s (Vector s a)
-{-# INLINE unsafeNewWith #-}
-unsafeNewWith (I# n#) x = ST (\s# ->
-    case newArray# n# x s# of
-      (# s2#, arr# #) -> (# s2#, Vector 0 (I# n#) arr# #)
-  )
-
diff --git a/Data/Vector/Primitive.hs b/Data/Vector/Primitive.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Primitive.hs
@@ -0,0 +1,435 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
+
+-- |
+-- Module      : Data.Vector.Primitive
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- Unboxed vectors of primitive types.
+--
+
+module Data.Vector.Primitive (
+  Vector, MVector(..), Prim,
+
+  -- * Length information
+  length, null,
+
+  -- * Construction
+  empty, singleton, cons, snoc, replicate, (++), copy,
+
+  -- * Accessing individual elements
+  (!), head, last,
+
+  -- * Subvectors
+  slice, init, tail, take, drop,
+
+  -- * Permutations
+  accum, (//), backpermute, reverse,
+
+  -- * Mapping
+  map, concatMap,
+
+  -- * Zipping and unzipping
+  zipWith, zipWith3,
+
+  -- * Filtering
+  filter, takeWhile, dropWhile,
+
+  -- * Searching
+  elem, notElem, find, findIndex,
+
+  -- * Folding
+  foldl, foldl1, foldl', foldl1', foldr, foldr1,
+
+  -- * Specialised folds
+  sum, product, maximum, minimum,
+
+  -- * Unfolding
+  unfoldr,
+
+  -- * Scans
+  prescanl, prescanl',
+  postscanl, postscanl',
+  scanl, scanl', scanl1, scanl1',
+
+  -- * Enumeration
+  enumFromTo, enumFromThenTo,
+
+  -- * Conversion to/from lists
+  toList, fromList
+) where
+
+import qualified Data.Vector.Generic           as G
+import           Data.Vector.Primitive.Mutable ( MVector(..) )
+import           Data.Primitive.ByteArray
+import           Data.Primitive ( Prim )
+
+import Control.Monad.ST ( runST )
+
+import Prelude hiding ( length, null,
+                        replicate, (++),
+                        head, last,
+                        init, tail, take, drop, reverse,
+                        map, concatMap,
+                        zipWith, zipWith3, zip, zip3, unzip, unzip3,
+                        filter, takeWhile, dropWhile,
+                        elem, notElem,
+                        foldl, foldl1, foldr, foldr1,
+                        sum, product, minimum, maximum,
+                        scanl, scanl1,
+                        enumFromTo, enumFromThenTo )
+
+import qualified Prelude
+
+-- | Unboxed vectors of primitive types
+data Vector a = Vector {-# UNPACK #-} !Int
+                       {-# UNPACK #-} !Int
+                       {-# UNPACK #-} !ByteArray
+
+instance (Show a, Prim a) => Show (Vector a) where
+    show = (Prelude.++ " :: Data.Vector.Primitive.Vector") . ("fromList " Prelude.++) . show . toList
+
+instance Prim a => G.Vector Vector a where
+  {-# INLINE vnew #-}
+  vnew init = runST (do
+                       MVector i n marr <- init
+                       arr <- unsafeFreezeByteArray marr
+                       return (Vector i n arr))
+
+  {-# INLINE vlength #-}
+  vlength (Vector _ n _) = n
+
+  {-# INLINE unsafeSlice #-}
+  unsafeSlice (Vector i _ arr) j n = Vector (i+j) n arr
+
+  {-# INLINE unsafeIndexM #-}
+  unsafeIndexM (Vector i _ arr) j = return (indexByteArray arr (i+j))
+
+instance (Prim a, Eq a) => Eq (Vector a) where
+  {-# INLINE (==) #-}
+  (==) = G.eq
+
+instance (Prim a, Ord a) => Ord (Vector a) where
+  {-# INLINE compare #-}
+  compare = G.cmp
+
+-- Length
+-- ------
+
+length :: Prim a => Vector a -> Int
+{-# INLINE length #-}
+length = G.length
+
+null :: Prim a => Vector a -> Bool
+{-# INLINE null #-}
+null = G.null
+
+-- Construction
+-- ------------
+
+-- | Empty vector
+empty :: Prim a => Vector a
+{-# INLINE empty #-}
+empty = G.empty
+
+-- | Vector with exaclty one element
+singleton :: Prim a => a -> Vector a
+{-# INLINE singleton #-}
+singleton = G.singleton
+
+-- | Vector of the given length with the given value in each position
+replicate :: Prim a => Int -> a -> Vector a
+{-# INLINE replicate #-}
+replicate = G.replicate
+
+-- | Prepend an element
+cons :: Prim a => a -> Vector a -> Vector a
+{-# INLINE cons #-}
+cons = G.cons
+
+-- | Append an element
+snoc :: Prim a => Vector a -> a -> Vector a
+{-# INLINE snoc #-}
+snoc = G.snoc
+
+infixr 5 ++
+-- | Concatenate two vectors
+(++) :: Prim a => Vector a -> Vector a -> Vector a
+{-# INLINE (++) #-}
+(++) = (G.++)
+
+-- | Create a copy of a vector. Useful when dealing with slices.
+copy :: Prim a => Vector a -> Vector a
+{-# INLINE copy #-}
+copy = G.copy
+
+-- Accessing individual elements
+-- -----------------------------
+
+-- | Indexing
+(!) :: Prim a => Vector a -> Int -> a
+{-# INLINE (!) #-}
+(!) = (G.!)
+
+-- | First element
+head :: Prim a => Vector a -> a
+{-# INLINE head #-}
+head = G.head
+
+-- | Last element
+last :: Prim a => Vector a -> a
+{-# INLINE last #-}
+last = G.last
+
+-- Subarrays
+-- ---------
+
+-- | Yield a part of the vector without copying it. Safer version of
+-- 'unsafeSlice'.
+slice :: Prim a => Vector a -> Int   -- ^ starting index
+                             -> Int   -- ^ length
+                             -> Vector a
+{-# INLINE slice #-}
+slice = G.slice
+
+-- | Yield all but the last element without copying.
+init :: Prim a => Vector a -> Vector a
+{-# INLINE init #-}
+init = G.init
+
+-- | All but the first element (without copying).
+tail :: Prim a => Vector a -> Vector a
+{-# INLINE tail #-}
+tail = G.tail
+
+-- | Yield the first @n@ elements without copying.
+take :: Prim a => Int -> Vector a -> Vector a
+{-# INLINE take #-}
+take = G.take
+
+-- | Yield all but the first @n@ elements without copying.
+drop :: Prim a => Int -> Vector a -> Vector a
+{-# INLINE drop #-}
+drop = G.drop
+
+-- Permutations
+-- ------------
+
+accum :: Prim a => (a -> b -> a) -> Vector a -> [(Int,b)] -> Vector a
+{-# INLINE accum #-}
+accum = G.accum
+
+(//) :: Prim a => Vector a -> [(Int, a)] -> Vector a
+{-# INLINE (//) #-}
+(//) = (G.//)
+
+backpermute :: Prim a => Vector a -> Vector Int -> Vector a
+{-# INLINE backpermute #-}
+backpermute = G.backpermute
+
+reverse :: Prim a => Vector a -> Vector a
+{-# INLINE reverse #-}
+reverse = G.reverse
+
+-- Mapping
+-- -------
+
+-- | Map a function over a vector
+map :: (Prim a, Prim b) => (a -> b) -> Vector a -> Vector b
+{-# INLINE map #-}
+map = G.map
+
+concatMap :: (Prim a, Prim b) => (a -> Vector b) -> Vector a -> Vector b
+{-# INLINE concatMap #-}
+concatMap = G.concatMap
+
+-- Zipping/unzipping
+-- -----------------
+
+-- | Zip two vectors with the given function.
+zipWith :: (Prim a, Prim b, Prim c)
+        => (a -> b -> c) -> Vector a -> Vector b -> Vector c
+{-# INLINE zipWith #-}
+zipWith = G.zipWith
+
+-- | Zip three vectors with the given function.
+zipWith3 :: (Prim a, Prim b, Prim c, Prim d)
+         => (a -> b -> c -> d) -> Vector a -> Vector b -> Vector c -> Vector d
+{-# INLINE zipWith3 #-}
+zipWith3 = G.zipWith3
+
+-- Filtering
+-- ---------
+
+-- | Drop elements which do not satisfy the predicate
+filter :: Prim a => (a -> Bool) -> Vector a -> Vector a
+{-# INLINE filter #-}
+filter = G.filter
+
+-- | Yield the longest prefix of elements satisfying the predicate.
+takeWhile :: Prim a => (a -> Bool) -> Vector a -> Vector a
+{-# INLINE takeWhile #-}
+takeWhile = G.takeWhile
+
+-- | Drop the longest prefix of elements that satisfy the predicate.
+dropWhile :: Prim a => (a -> Bool) -> Vector a -> Vector a
+{-# INLINE dropWhile #-}
+dropWhile = G.dropWhile
+
+-- Searching
+-- ---------
+
+infix 4 `elem`
+-- | Check whether the vector contains an element
+elem :: (Prim a, Eq a) => a -> Vector a -> Bool
+{-# INLINE elem #-}
+elem = G.elem
+
+infix 4 `notElem`
+-- | Inverse of `elem`
+notElem :: (Prim a, Eq a) => a -> Vector a -> Bool
+{-# INLINE notElem #-}
+notElem = G.notElem
+
+-- | Yield 'Just' the first element matching the predicate or 'Nothing' if no
+-- such element exists.
+find :: Prim a => (a -> Bool) -> Vector a -> Maybe a
+{-# INLINE find #-}
+find = G.find
+
+-- | Yield 'Just' the index of the first element matching the predicate or
+-- 'Nothing' if no such element exists.
+findIndex :: Prim a => (a -> Bool) -> Vector a -> Maybe Int
+{-# INLINE findIndex #-}
+findIndex = G.findIndex
+
+-- Folding
+-- -------
+
+-- | Left fold
+foldl :: Prim b => (a -> b -> a) -> a -> Vector b -> a
+{-# INLINE foldl #-}
+foldl = G.foldl
+
+-- | Lefgt fold on non-empty vectors
+foldl1 :: Prim a => (a -> a -> a) -> Vector a -> a
+{-# INLINE foldl1 #-}
+foldl1 = G.foldl1
+
+-- | Left fold with strict accumulator
+foldl' :: Prim b => (a -> b -> a) -> a -> Vector b -> a
+{-# INLINE foldl' #-}
+foldl' = G.foldl'
+
+-- | Left fold on non-empty vectors with strict accumulator
+foldl1' :: Prim a => (a -> a -> a) -> Vector a -> a
+{-# INLINE foldl1' #-}
+foldl1' = G.foldl1'
+
+-- | Right fold
+foldr :: Prim a => (a -> b -> b) -> b -> Vector a -> b
+{-# INLINE foldr #-}
+foldr = G.foldr
+
+-- | Right fold on non-empty vectors
+foldr1 :: Prim a => (a -> a -> a) -> Vector a -> a
+{-# INLINE foldr1 #-}
+foldr1 = G.foldr1
+
+-- Specialised folds
+-- -----------------
+
+sum :: (Prim a, Num a) => Vector a -> a
+{-# INLINE sum #-}
+sum = G.sum
+
+product :: (Prim a, Num a) => Vector a -> a
+{-# INLINE product #-}
+product = G.product
+
+maximum :: (Prim a, Ord a) => Vector a -> a
+{-# INLINE maximum #-}
+maximum = G.maximum
+
+minimum :: (Prim a, Ord a) => Vector a -> a
+{-# INLINE minimum #-}
+minimum = G.minimum
+
+-- Unfolding
+-- ---------
+
+unfoldr :: Prim a => (b -> Maybe (a, b)) -> b -> Vector a
+{-# INLINE unfoldr #-}
+unfoldr = G.unfoldr
+
+-- Scans
+-- -----
+
+-- | Prefix scan
+prescanl :: (Prim a, Prim b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE prescanl #-}
+prescanl = G.prescanl
+
+-- | Prefix scan with strict accumulator
+prescanl' :: (Prim a, Prim b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE prescanl' #-}
+prescanl' = G.prescanl'
+
+-- | Suffix scan
+postscanl :: (Prim a, Prim b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE postscanl #-}
+postscanl = G.postscanl
+
+-- | Suffix scan with strict accumulator
+postscanl' :: (Prim a, Prim b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE postscanl' #-}
+postscanl' = G.postscanl'
+
+-- | Haskell-style scan
+scanl :: (Prim a, Prim b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE scanl #-}
+scanl = G.scanl
+
+-- | Haskell-style scan with strict accumulator
+scanl' :: (Prim a, Prim b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE scanl' #-}
+scanl' = G.scanl'
+
+-- | Scan over a non-empty 'Vector'
+scanl1 :: Prim a => (a -> a -> a) -> Vector a -> Vector a
+{-# INLINE scanl1 #-}
+scanl1 = G.scanl1
+
+-- | Scan over a non-empty 'Vector' with a strict accumulator
+scanl1' :: Prim a => (a -> a -> a) -> Vector a -> Vector a
+{-# INLINE scanl1' #-}
+scanl1' = G.scanl1'
+
+-- Enumeration
+-- -----------
+
+enumFromTo :: (Prim a, Enum a) => a -> a -> Vector a
+{-# INLINE enumFromTo #-}
+enumFromTo = G.enumFromTo
+
+enumFromThenTo :: (Prim a, Enum a) => a -> a -> a -> Vector a
+{-# INLINE enumFromThenTo #-}
+enumFromThenTo = G.enumFromThenTo
+
+-- Conversion to/from lists
+-- ------------------------
+
+-- | Convert a vector to a list
+toList :: Prim a => Vector a -> [a]
+{-# INLINE toList #-}
+toList = G.toList
+
+-- | Convert a list to a vector
+fromList :: Prim a => [a] -> Vector a
+{-# INLINE fromList #-}
+fromList = G.fromList
+
diff --git a/Data/Vector/Primitive/Mutable.hs b/Data/Vector/Primitive/Mutable.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Primitive/Mutable.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, ScopedTypeVariables #-}
+
+-- |
+-- Module      : Data.Vector.Primitive.Mutable
+-- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- Mutable primitive vectors.
+--
+
+module Data.Vector.Primitive.Mutable ( MVector(..), IOVector, STVector )
+where
+
+import qualified Data.Vector.Generic.Mutable as G
+import           Data.Primitive.ByteArray
+import           Data.Primitive ( Prim, sizeOf )
+import           Control.Monad.Primitive
+import           Control.Monad.ST ( ST )
+
+-- | Mutable unboxed vectors. They live in the 'ST' monad.
+data MVector m a = MVector {-# UNPACK #-} !Int
+                         {-# UNPACK #-} !Int
+                         {-# UNPACK #-} !(MutableByteArray m)
+
+type IOVector = MVector IO
+type STVector s = MVector (ST s)
+
+instance Prim a => G.MVectorPure (MVector m) a where
+  length (MVector _ n _) = n
+  unsafeSlice (MVector i _ arr) j m = MVector (i+j) m arr
+
+  {-# INLINE overlaps #-}
+  overlaps (MVector i m arr1) (MVector j n arr2)
+    = sameMutableByteArray arr1 arr2
+      && (between i j (j+n) || between j i (i+m))
+    where
+      between x y z = x >= y && x < z
+
+
+instance (Prim a, PrimMonad m) => G.MVector (MVector m) m a where
+  {-# INLINE unsafeNew #-}
+  unsafeNew n = do
+                  arr <- newByteArray (n * sizeOf (undefined :: a))
+                  return (MVector 0 n arr)
+
+  {-# INLINE unsafeRead #-}
+  unsafeRead (MVector i _ arr) j = readByteArray arr (i+j)
+
+  {-# INLINE unsafeWrite #-}
+  unsafeWrite (MVector i _ arr) j x = writeByteArray arr (i+j) x
+
+  {-# INLINE clear #-}
+  clear _ = return ()
+
diff --git a/Data/Vector/Storable.hs b/Data/Vector/Storable.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Storable.hs
@@ -0,0 +1,449 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
+
+-- |
+-- Module      : Data.Vector.Storable
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- 'Storable'-based vectors.
+--
+
+module Data.Vector.Storable (
+  Vector, MVector(..), Storable,
+
+  -- * Length information
+  length, null,
+
+  -- * Construction
+  empty, singleton, cons, snoc, replicate, (++), copy,
+
+  -- * Accessing individual elements
+  (!), head, last,
+
+  -- * Subvectors
+  slice, init, tail, take, drop,
+
+  -- * Permutations
+  accum, (//), backpermute, reverse,
+
+  -- * Mapping
+  map, concatMap,
+
+  -- * Zipping and unzipping
+  zipWith, zipWith3,
+
+  -- * Filtering
+  filter, takeWhile, dropWhile,
+
+  -- * Searching
+  elem, notElem, find, findIndex,
+
+  -- * Folding
+  foldl, foldl1, foldl', foldl1', foldr, foldr1,
+
+  -- * Specialised folds
+  and, or, sum, product, maximum, minimum,
+
+  -- * Unfolding
+  unfoldr,
+
+  -- * Scans
+  prescanl, prescanl',
+  postscanl, postscanl',
+  scanl, scanl', scanl1, scanl1',
+
+  -- * Enumeration
+  enumFromTo, enumFromThenTo,
+
+  -- * Conversion to/from lists
+  toList, fromList
+) where
+
+import qualified Data.Vector.Generic          as G
+import           Data.Vector.Storable.Mutable ( MVector(..) )
+import Data.Vector.Storable.Internal
+
+import Foreign.Storable
+import Foreign.ForeignPtr
+
+import System.IO.Unsafe ( unsafePerformIO )
+
+import Prelude hiding ( length, null,
+                        replicate, (++),
+                        head, last,
+                        init, tail, take, drop, reverse,
+                        map, concatMap,
+                        zipWith, zipWith3, zip, zip3, unzip, unzip3,
+                        filter, takeWhile, dropWhile,
+                        elem, notElem,
+                        foldl, foldl1, foldr, foldr1,
+                        and, or, sum, product, minimum, maximum,
+                        scanl, scanl1,
+                        enumFromTo, enumFromThenTo )
+
+import qualified Prelude
+
+-- | 'Storable'-based vectors
+data Vector a = Vector {-# UNPACK #-} !Int
+                       {-# UNPACK #-} !Int
+                       {-# UNPACK #-} !(ForeignPtr a)
+
+instance (Show a, Storable a) => Show (Vector a) where
+  show = (Prelude.++ " :: Data.Vector.Storable.Vector")
+       . ("fromList " Prelude.++)
+       . show
+       . toList
+
+instance Storable a => G.Vector Vector a where
+  {-# INLINE vnew #-}
+  vnew init = unsafePerformIO (do
+                                 MVector i n p <- init
+                                 return (Vector i n p))
+
+  {-# INLINE vlength #-}
+  vlength (Vector _ n _) = n
+
+  {-# INLINE unsafeSlice #-}
+  unsafeSlice (Vector i _ p) j n = Vector (i+j) n p
+
+  {-# INLINE unsafeIndexM #-}
+  unsafeIndexM (Vector i _ p) j = return
+                                . inlinePerformIO
+                                $ withForeignPtr p (`peekElemOff` (i+j))
+
+instance (Storable a, Eq a) => Eq (Vector a) where
+  {-# INLINE (==) #-}
+  (==) = G.eq
+
+instance (Storable a, Ord a) => Ord (Vector a) where
+  {-# INLINE compare #-}
+  compare = G.cmp
+
+-- Length
+-- ------
+
+length :: Storable a => Vector a -> Int
+{-# INLINE length #-}
+length = G.length
+
+null :: Storable a => Vector a -> Bool
+{-# INLINE null #-}
+null = G.null
+
+-- Construction
+-- ------------
+
+-- | Empty vector
+empty :: Storable a => Vector a
+{-# INLINE empty #-}
+empty = G.empty
+
+-- | Vector with exaclty one element
+singleton :: Storable a => a -> Vector a
+{-# INLINE singleton #-}
+singleton = G.singleton
+
+-- | Vector of the given length with the given value in each position
+replicate :: Storable a => Int -> a -> Vector a
+{-# INLINE replicate #-}
+replicate = G.replicate
+
+-- | Prepend an element
+cons :: Storable a => a -> Vector a -> Vector a
+{-# INLINE cons #-}
+cons = G.cons
+
+-- | Append an element
+snoc :: Storable a => Vector a -> a -> Vector a
+{-# INLINE snoc #-}
+snoc = G.snoc
+
+infixr 5 ++
+-- | Concatenate two vectors
+(++) :: Storable a => Vector a -> Vector a -> Vector a
+{-# INLINE (++) #-}
+(++) = (G.++)
+
+-- | Create a copy of a vector. Useful when dealing with slices.
+copy :: Storable a => Vector a -> Vector a
+{-# INLINE copy #-}
+copy = G.copy
+
+-- Accessing individual elements
+-- -----------------------------
+
+-- | Indexing
+(!) :: Storable a => Vector a -> Int -> a
+{-# INLINE (!) #-}
+(!) = (G.!)
+
+-- | First element
+head :: Storable a => Vector a -> a
+{-# INLINE head #-}
+head = G.head
+
+-- | Last element
+last :: Storable a => Vector a -> a
+{-# INLINE last #-}
+last = G.last
+
+-- Subarrays
+-- ---------
+
+-- | Yield a part of the vector without copying it. Safer version of
+-- 'unsafeSlice'.
+slice :: Storable a => Vector a -> Int   -- ^ starting index
+                             -> Int   -- ^ length
+                             -> Vector a
+{-# INLINE slice #-}
+slice = G.slice
+
+-- | Yield all but the last element without copying.
+init :: Storable a => Vector a -> Vector a
+{-# INLINE init #-}
+init = G.init
+
+-- | All but the first element (without copying).
+tail :: Storable a => Vector a -> Vector a
+{-# INLINE tail #-}
+tail = G.tail
+
+-- | Yield the first @n@ elements without copying.
+take :: Storable a => Int -> Vector a -> Vector a
+{-# INLINE take #-}
+take = G.take
+
+-- | Yield all but the first @n@ elements without copying.
+drop :: Storable a => Int -> Vector a -> Vector a
+{-# INLINE drop #-}
+drop = G.drop
+
+-- Permutations
+-- ------------
+
+accum :: Storable a => (a -> b -> a) -> Vector a -> [(Int,b)] -> Vector a
+{-# INLINE accum #-}
+accum = G.accum
+
+(//) :: Storable a => Vector a -> [(Int, a)] -> Vector a
+{-# INLINE (//) #-}
+(//) = (G.//)
+
+backpermute :: Storable a => Vector a -> Vector Int -> Vector a
+{-# INLINE backpermute #-}
+backpermute = G.backpermute
+
+reverse :: Storable a => Vector a -> Vector a
+{-# INLINE reverse #-}
+reverse = G.reverse
+
+-- Mapping
+-- -------
+
+-- | Map a function over a vector
+map :: (Storable a, Storable b) => (a -> b) -> Vector a -> Vector b
+{-# INLINE map #-}
+map = G.map
+
+concatMap :: (Storable a, Storable b) => (a -> Vector b) -> Vector a -> Vector b
+{-# INLINE concatMap #-}
+concatMap = G.concatMap
+
+-- Zipping/unzipping
+-- -----------------
+
+-- | Zip two vectors with the given function.
+zipWith :: (Storable a, Storable b, Storable c)
+        => (a -> b -> c) -> Vector a -> Vector b -> Vector c
+{-# INLINE zipWith #-}
+zipWith = G.zipWith
+
+-- | Zip three vectors with the given function.
+zipWith3 :: (Storable a, Storable b, Storable c, Storable d)
+         => (a -> b -> c -> d) -> Vector a -> Vector b -> Vector c -> Vector d
+{-# INLINE zipWith3 #-}
+zipWith3 = G.zipWith3
+
+-- Filtering
+-- ---------
+
+-- | Drop elements which do not satisfy the predicate
+filter :: Storable a => (a -> Bool) -> Vector a -> Vector a
+{-# INLINE filter #-}
+filter = G.filter
+
+-- | Yield the longest prefix of elements satisfying the predicate.
+takeWhile :: Storable a => (a -> Bool) -> Vector a -> Vector a
+{-# INLINE takeWhile #-}
+takeWhile = G.takeWhile
+
+-- | Drop the longest prefix of elements that satisfy the predicate.
+dropWhile :: Storable a => (a -> Bool) -> Vector a -> Vector a
+{-# INLINE dropWhile #-}
+dropWhile = G.dropWhile
+
+-- Searching
+-- ---------
+
+infix 4 `elem`
+-- | Check whether the vector contains an element
+elem :: (Storable a, Eq a) => a -> Vector a -> Bool
+{-# INLINE elem #-}
+elem = G.elem
+
+infix 4 `notElem`
+-- | Inverse of `elem`
+notElem :: (Storable a, Eq a) => a -> Vector a -> Bool
+{-# INLINE notElem #-}
+notElem = G.notElem
+
+-- | Yield 'Just' the first element matching the predicate or 'Nothing' if no
+-- such element exists.
+find :: Storable a => (a -> Bool) -> Vector a -> Maybe a
+{-# INLINE find #-}
+find = G.find
+
+-- | Yield 'Just' the index of the first element matching the predicate or
+-- 'Nothing' if no such element exists.
+findIndex :: Storable a => (a -> Bool) -> Vector a -> Maybe Int
+{-# INLINE findIndex #-}
+findIndex = G.findIndex
+
+-- Folding
+-- -------
+
+-- | Left fold
+foldl :: Storable b => (a -> b -> a) -> a -> Vector b -> a
+{-# INLINE foldl #-}
+foldl = G.foldl
+
+-- | Lefgt fold on non-empty vectors
+foldl1 :: Storable a => (a -> a -> a) -> Vector a -> a
+{-# INLINE foldl1 #-}
+foldl1 = G.foldl1
+
+-- | Left fold with strict accumulator
+foldl' :: Storable b => (a -> b -> a) -> a -> Vector b -> a
+{-# INLINE foldl' #-}
+foldl' = G.foldl'
+
+-- | Left fold on non-empty vectors with strict accumulator
+foldl1' :: Storable a => (a -> a -> a) -> Vector a -> a
+{-# INLINE foldl1' #-}
+foldl1' = G.foldl1'
+
+-- | Right fold
+foldr :: Storable a => (a -> b -> b) -> b -> Vector a -> b
+{-# INLINE foldr #-}
+foldr = G.foldr
+
+-- | Right fold on non-empty vectors
+foldr1 :: Storable a => (a -> a -> a) -> Vector a -> a
+{-# INLINE foldr1 #-}
+foldr1 = G.foldr1
+
+-- Specialised folds
+-- -----------------
+
+and :: Vector Bool -> Bool
+{-# INLINE and #-}
+and = G.and
+
+or :: Vector Bool -> Bool
+{-# INLINE or #-}
+or = G.or
+
+sum :: (Storable a, Num a) => Vector a -> a
+{-# INLINE sum #-}
+sum = G.sum
+
+product :: (Storable a, Num a) => Vector a -> a
+{-# INLINE product #-}
+product = G.product
+
+maximum :: (Storable a, Ord a) => Vector a -> a
+{-# INLINE maximum #-}
+maximum = G.maximum
+
+minimum :: (Storable a, Ord a) => Vector a -> a
+{-# INLINE minimum #-}
+minimum = G.minimum
+
+-- Unfolding
+-- ---------
+
+unfoldr :: Storable a => (b -> Maybe (a, b)) -> b -> Vector a
+{-# INLINE unfoldr #-}
+unfoldr = G.unfoldr
+
+-- Scans
+-- -----
+
+-- | Prefix scan
+prescanl :: (Storable a, Storable b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE prescanl #-}
+prescanl = G.prescanl
+
+-- | Prefix scan with strict accumulator
+prescanl' :: (Storable a, Storable b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE prescanl' #-}
+prescanl' = G.prescanl'
+
+-- | Suffix scan
+postscanl :: (Storable a, Storable b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE postscanl #-}
+postscanl = G.postscanl
+
+-- | Suffix scan with strict accumulator
+postscanl' :: (Storable a, Storable b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE postscanl' #-}
+postscanl' = G.postscanl'
+
+-- | Haskell-style scan
+scanl :: (Storable a, Storable b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE scanl #-}
+scanl = G.scanl
+
+-- | Haskell-style scan with strict accumulator
+scanl' :: (Storable a, Storable b) => (a -> b -> a) -> a -> Vector b -> Vector a
+{-# INLINE scanl' #-}
+scanl' = G.scanl'
+
+-- | Scan over a non-empty 'Vector'
+scanl1 :: Storable a => (a -> a -> a) -> Vector a -> Vector a
+{-# INLINE scanl1 #-}
+scanl1 = G.scanl1
+
+-- | Scan over a non-empty 'Vector' with a strict accumulator
+scanl1' :: Storable a => (a -> a -> a) -> Vector a -> Vector a
+{-# INLINE scanl1' #-}
+scanl1' = G.scanl1'
+
+-- Enumeration
+-- -----------
+
+enumFromTo :: (Storable a, Enum a) => a -> a -> Vector a
+{-# INLINE enumFromTo #-}
+enumFromTo = G.enumFromTo
+
+enumFromThenTo :: (Storable a, Enum a) => a -> a -> a -> Vector a
+{-# INLINE enumFromThenTo #-}
+enumFromThenTo = G.enumFromThenTo
+
+-- Conversion to/from lists
+-- ------------------------
+
+-- | Convert a vector to a list
+toList :: Storable a => Vector a -> [a]
+{-# INLINE toList #-}
+toList = G.toList
+
+-- | Convert a list to a vector
+fromList :: Storable a => [a] -> Vector a
+{-# INLINE fromList #-}
+fromList = G.fromList
+
diff --git a/Data/Vector/Storable/Internal.hs b/Data/Vector/Storable/Internal.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Storable/Internal.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE MagicHash, UnboxedTuples #-}
+
+-- |
+-- Module      : Data.Vector.Storable.Internal
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- Ugly internal utility functions for implementing 'Storable'-based vectors.
+--
+
+module Data.Vector.Storable.Internal
+where
+
+import GHC.Base         ( realWorld# )
+import GHC.IOBase       ( IO(..) )
+
+-- Stolen from the ByteString library
+inlinePerformIO :: IO a -> a
+{-# INLINE inlinePerformIO #-}
+inlinePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
+
diff --git a/Data/Vector/Storable/Mutable.hs b/Data/Vector/Storable/Mutable.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Storable/Mutable.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
+
+-- |
+-- Module      : Data.Vector.Storable.Mutable
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- Mutable vectors based on Storable.
+--
+
+module Data.Vector.Storable.Mutable( MVector(..) )
+where
+
+import qualified Data.Vector.Generic.Mutable as G
+
+import Foreign.Storable
+import Foreign.ForeignPtr
+
+-- | Mutable 'Storable'-based vectors in the 'IO' monad.
+data MVector a = MVector {-# UNPACK #-} !Int
+                       {-# UNPACK #-} !Int
+                       {-# UNPACK #-} !(ForeignPtr a)
+
+instance G.MVectorPure MVector a where
+  {-# INLINE length #-}
+  length (MVector _ n _) = n
+
+  {-# INLINE unsafeSlice #-}
+  unsafeSlice (MVector i _ p) j m = MVector (i+j) m p
+
+  -- FIXME: implement this properly
+  {-# INLINE overlaps #-}
+  overlaps (MVector i m p) (MVector j n q)
+    = True
+
+instance Storable a => G.MVector MVector IO a where
+  {-# INLINE unsafeNew #-}
+  unsafeNew n = MVector 0 n `fmap` mallocForeignPtrArray n
+
+  {-# INLINE unsafeRead #-}
+  unsafeRead (MVector i n p) j = withForeignPtr p $ \ptr ->
+                                peekElemOff ptr (i+j)
+     
+  {-# INLINE unsafeWrite #-}
+  unsafeWrite (MVector i n p) j x = withForeignPtr p $ \ptr ->
+                                   pokeElemOff ptr (i+j) x 
+
+  {-# INLINE clear #-}
+  clear _ = return ()
+
diff --git a/Data/Vector/Unboxed.hs b/Data/Vector/Unboxed.hs
deleted file mode 100644
--- a/Data/Vector/Unboxed.hs
+++ /dev/null
@@ -1,416 +0,0 @@
-{-# LANGUAGE MagicHash, UnboxedTuples, FlexibleInstances, MultiParamTypeClasses #-}
-
--- |
--- Module      : Data.Vector.Unboxed
--- Copyright   : (c) Roman Leshchinskiy 2008
--- License     : BSD-style
---
--- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
--- Stability   : experimental
--- Portability : non-portable
--- 
--- Unboxed vectors based on 'Unbox'.
---
-
-module Data.Vector.Unboxed (
-  Vector,
-
-  -- * Length information
-  length, null,
-
-  -- * Construction
-  empty, singleton, cons, snoc, replicate, (++), copy,
-
-  -- * Accessing individual elements
-  (!), head, last,
-
-  -- * Subvectors
-  slice, init, tail, take, drop,
-
-  -- * Permutations
-  accum, (//), backpermute, reverse,
-
-  -- * Mapping
-  map, concatMap,
-
-  -- * Zipping and unzipping
-  zipWith, zipWith3,
-
-  -- * Filtering
-  filter, takeWhile, dropWhile,
-
-  -- * Searching
-  elem, notElem, find, findIndex,
-
-  -- * Folding
-  foldl, foldl1, foldl', foldl1', foldr, foldr1,
-
-  -- * Specialised folds
-  {-and, or,-} sum, product, maximum, minimum,
-
-  -- * Unfolding
-  unfoldr,
-
-  -- * Scans
-  prescanl, prescanl',
-
-  -- * Enumeration
-  enumFromTo, enumFromThenTo,
-
-  -- * Conversion to/from lists
-  toList, fromList
-) where
-
-import           Data.Vector.IVector ( IVector(..) )
-import qualified Data.Vector.IVector            as IV
-import qualified Data.Vector.Unboxed.Mutable.ST as Mut
-import           Data.Vector.Unboxed.Unbox
-
-import Control.Monad.ST ( runST )
-
-import GHC.ST   ( ST(..) )
-import GHC.Prim ( ByteArray#, unsafeFreezeByteArray#, (+#) )
-import GHC.Base ( Int(..) )
-
-import Prelude hiding ( length, null,
-                        replicate, (++),
-                        head, last,
-                        init, tail, take, drop, reverse,
-                        map, concatMap,
-                        zipWith, zipWith3, zip, zip3, unzip, unzip3,
-                        filter, takeWhile, dropWhile,
-                        elem, notElem,
-                        foldl, foldl1, foldr, foldr1,
-                        and, or, sum, product, minimum, maximum,
-                        enumFromTo, enumFromThenTo )
-
-import qualified Prelude
-
--- | Unboxed vectors
-data Vector a = Vector {-# UNPACK #-} !Int
-                       {-# UNPACK #-} !Int
-                                      ByteArray#
-
-instance (Show a, Unbox a) => Show (Vector a) where
-    show = (Prelude.++ " :: Data.Vector.Unboxed.Vector") . ("fromList " Prelude.++) . show . toList
-
-instance Unbox a => IVector Vector a where
-  {-# INLINE vnew #-}
-  vnew init = runST (do
-                       Mut.Vector i n marr# <- init
-                       ST (\s# -> case unsafeFreezeByteArray# marr# s# of
-                            (# s2#, arr# #) -> (# s2#, Vector i n arr# #)))
-
-  {-# INLINE vlength #-}
-  vlength (Vector _ n _) = n
-
-  {-# INLINE unsafeSlice #-}
-  unsafeSlice (Vector i _ arr#) j n = Vector (i+j) n arr#
-
-  {-# INLINE unsafeIndexM #-}
-  unsafeIndexM (Vector (I# i#) _ arr#) (I# j#) = return (at# arr# (i# +# j#))
-
-instance (Unbox a, Eq a) => Eq (Vector a) where
-  {-# INLINE (==) #-}
-  (==) = IV.eq
-
-instance (Unbox a, Ord a) => Ord (Vector a) where
-  {-# INLINE compare #-}
-  compare = IV.cmp
-
--- Length
--- ------
-
-length :: Unbox a => Vector a -> Int
-{-# INLINE length #-}
-length = IV.length
-
-null :: Unbox a => Vector a -> Bool
-{-# INLINE null #-}
-null = IV.null
-
--- Construction
--- ------------
-
--- | Empty vector
-empty :: Unbox a => Vector a
-{-# INLINE empty #-}
-empty = IV.empty
-
--- | Vector with exaclty one element
-singleton :: Unbox a => a -> Vector a
-{-# INLINE singleton #-}
-singleton = IV.singleton
-
--- | Vector of the given length with the given value in each position
-replicate :: Unbox a => Int -> a -> Vector a
-{-# INLINE replicate #-}
-replicate = IV.replicate
-
--- | Prepend an element
-cons :: Unbox a => a -> Vector a -> Vector a
-{-# INLINE cons #-}
-cons = IV.cons
-
--- | Append an element
-snoc :: Unbox a => Vector a -> a -> Vector a
-{-# INLINE snoc #-}
-snoc = IV.snoc
-
-infixr 5 ++
--- | Concatenate two vectors
-(++) :: Unbox a => Vector a -> Vector a -> Vector a
-{-# INLINE (++) #-}
-(++) = (IV.++)
-
--- | Create a copy of a vector. Useful when dealing with slices.
-copy :: Unbox a => Vector a -> Vector a
-{-# INLINE copy #-}
-copy = IV.copy
-
--- Accessing individual elements
--- -----------------------------
-
--- | Indexing
-(!) :: Unbox a => Vector a -> Int -> a
-{-# INLINE (!) #-}
-(!) = (IV.!)
-
--- | First element
-head :: Unbox a => Vector a -> a
-{-# INLINE head #-}
-head = IV.head
-
--- | Last element
-last :: Unbox a => Vector a -> a
-{-# INLINE last #-}
-last = IV.last
-
--- Subarrays
--- ---------
-
--- | Yield a part of the vector without copying it. Safer version of
--- 'unsafeSlice'.
-slice :: Unbox a => Vector a -> Int   -- ^ starting index
-                             -> Int   -- ^ length
-                             -> Vector a
-{-# INLINE slice #-}
-slice = IV.slice
-
--- | Yield all but the last element without copying.
-init :: Unbox a => Vector a -> Vector a
-{-# INLINE init #-}
-init = IV.init
-
--- | All but the first element (without copying).
-tail :: Unbox a => Vector a -> Vector a
-{-# INLINE tail #-}
-tail = IV.tail
-
--- | Yield the first @n@ elements without copying.
-take :: Unbox a => Int -> Vector a -> Vector a
-{-# INLINE take #-}
-take = IV.take
-
--- | Yield all but the first @n@ elements without copying.
-drop :: Unbox a => Int -> Vector a -> Vector a
-{-# INLINE drop #-}
-drop = IV.drop
-
--- Permutations
--- ------------
-
-accum :: Unbox a => (a -> b -> a) -> Vector a -> [(Int,b)] -> Vector a
-{-# INLINE accum #-}
-accum = IV.accum
-
-(//) :: Unbox a => Vector a -> [(Int, a)] -> Vector a
-{-# INLINE (//) #-}
-(//) = (IV.//)
-
-backpermute :: Unbox a => Vector a -> Vector Int -> Vector a
-{-# INLINE backpermute #-}
-backpermute = IV.backpermute
-
-reverse :: Unbox a => Vector a -> Vector a
-{-# INLINE reverse #-}
-reverse = IV.reverse
-
--- Mapping
--- -------
-
--- | Map a function over a vector
-map :: (Unbox a, Unbox b) => (a -> b) -> Vector a -> Vector b
-{-# INLINE map #-}
-map = IV.map
-
-concatMap :: (Unbox a, Unbox b) => (a -> Vector b) -> Vector a -> Vector b
-{-# INLINE concatMap #-}
-concatMap = IV.concatMap
-
--- Zipping/unzipping
--- -----------------
-
--- | Zip two vectors with the given function.
-zipWith :: (Unbox a, Unbox b, Unbox c)
-        => (a -> b -> c) -> Vector a -> Vector b -> Vector c
-{-# INLINE zipWith #-}
-zipWith = IV.zipWith
-
--- | Zip three vectors with the given function.
-zipWith3 :: (Unbox a, Unbox b, Unbox c, Unbox d)
-         => (a -> b -> c -> d) -> Vector a -> Vector b -> Vector c -> Vector d
-{-# INLINE zipWith3 #-}
-zipWith3 = IV.zipWith3
-
--- Filtering
--- ---------
-
--- | Drop elements which do not satisfy the predicate
-filter :: Unbox a => (a -> Bool) -> Vector a -> Vector a
-{-# INLINE filter #-}
-filter = IV.filter
-
--- | Yield the longest prefix of elements satisfying the predicate.
-takeWhile :: Unbox a => (a -> Bool) -> Vector a -> Vector a
-{-# INLINE takeWhile #-}
-takeWhile = IV.takeWhile
-
--- | Drop the longest prefix of elements that satisfy the predicate.
-dropWhile :: Unbox a => (a -> Bool) -> Vector a -> Vector a
-{-# INLINE dropWhile #-}
-dropWhile = IV.dropWhile
-
--- Searching
--- ---------
-
-infix 4 `elem`
--- | Check whether the vector contains an element
-elem :: (Unbox a, Eq a) => a -> Vector a -> Bool
-{-# INLINE elem #-}
-elem = IV.elem
-
-infix 4 `notElem`
--- | Inverse of `elem`
-notElem :: (Unbox a, Eq a) => a -> Vector a -> Bool
-{-# INLINE notElem #-}
-notElem = IV.notElem
-
--- | Yield 'Just' the first element matching the predicate or 'Nothing' if no
--- such element exists.
-find :: Unbox a => (a -> Bool) -> Vector a -> Maybe a
-{-# INLINE find #-}
-find = IV.find
-
--- | Yield 'Just' the index of the first element matching the predicate or
--- 'Nothing' if no such element exists.
-findIndex :: Unbox a => (a -> Bool) -> Vector a -> Maybe Int
-{-# INLINE findIndex #-}
-findIndex = IV.findIndex
-
--- Folding
--- -------
-
--- | Left fold
-foldl :: Unbox b => (a -> b -> a) -> a -> Vector b -> a
-{-# INLINE foldl #-}
-foldl = IV.foldl
-
--- | Lefgt fold on non-empty vectors
-foldl1 :: Unbox a => (a -> a -> a) -> Vector a -> a
-{-# INLINE foldl1 #-}
-foldl1 = IV.foldl1
-
--- | Left fold with strict accumulator
-foldl' :: Unbox b => (a -> b -> a) -> a -> Vector b -> a
-{-# INLINE foldl' #-}
-foldl' = IV.foldl'
-
--- | Left fold on non-empty vectors with strict accumulator
-foldl1' :: Unbox a => (a -> a -> a) -> Vector a -> a
-{-# INLINE foldl1' #-}
-foldl1' = IV.foldl1'
-
--- | Right fold
-foldr :: Unbox a => (a -> b -> b) -> b -> Vector a -> b
-{-# INLINE foldr #-}
-foldr = IV.foldr
-
--- | Right fold on non-empty vectors
-foldr1 :: Unbox a => (a -> a -> a) -> Vector a -> a
-{-# INLINE foldr1 #-}
-foldr1 = IV.foldr1
-
--- Specialised folds
--- -----------------
-
-{-
-and :: Vector Bool -> Bool
-{-# INLINE and #-}
-and = IV.and
-
-or :: Vector Bool -> Bool
-{-# INLINE or #-}
-or = IV.or
--}
-
-sum :: (Unbox a, Num a) => Vector a -> a
-{-# INLINE sum #-}
-sum = IV.sum
-
-product :: (Unbox a, Num a) => Vector a -> a
-{-# INLINE product #-}
-product = IV.product
-
-maximum :: (Unbox a, Ord a) => Vector a -> a
-{-# INLINE maximum #-}
-maximum = IV.maximum
-
-minimum :: (Unbox a, Ord a) => Vector a -> a
-{-# INLINE minimum #-}
-minimum = IV.minimum
-
--- Unfolding
--- ---------
-
-unfoldr :: Unbox a => (b -> Maybe (a, b)) -> b -> Vector a
-{-# INLINE unfoldr #-}
-unfoldr = IV.unfoldr
-
--- Scans
--- -----
-
--- | Prefix scan
-prescanl :: (Unbox a, Unbox b) => (a -> b -> a) -> a -> Vector b -> Vector a
-{-# INLINE prescanl #-}
-prescanl = IV.prescanl
-
--- | Prefix scan with strict accumulator
-prescanl' :: (Unbox a, Unbox b) => (a -> b -> a) -> a -> Vector b -> Vector a
-{-# INLINE prescanl' #-}
-prescanl' = IV.prescanl'
-
--- Enumeration
--- -----------
-
-enumFromTo :: (Unbox a, Enum a) => a -> a -> Vector a
-{-# INLINE enumFromTo #-}
-enumFromTo = IV.enumFromTo
-
-enumFromThenTo :: (Unbox a, Enum a) => a -> a -> a -> Vector a
-{-# INLINE enumFromThenTo #-}
-enumFromThenTo = IV.enumFromThenTo
-
--- Conversion to/from lists
--- ------------------------
-
--- | Convert a vector to a list
-toList :: Unbox a => Vector a -> [a]
-{-# INLINE toList #-}
-toList = IV.toList
-
--- | Convert a list to a vector
-fromList :: Unbox a => [a] -> Vector a
-{-# INLINE fromList #-}
-fromList = IV.fromList
-
diff --git a/Data/Vector/Unboxed/Mutable/IO.hs b/Data/Vector/Unboxed/Mutable/IO.hs
deleted file mode 100644
--- a/Data/Vector/Unboxed/Mutable/IO.hs
+++ /dev/null
@@ -1,59 +0,0 @@
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
-
--- |
--- Module      : Data.Vector.Mutable.Unboxed.IO
--- Copyright   : (c) Roman Leshchinskiy 2009
--- License     : BSD-style
---
--- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
--- Stability   : experimental
--- Portability : non-portable
--- 
--- Mutable unboxed vectors in the IO monad.
---
-
-module Data.Vector.Unboxed.Mutable.IO ( Vector(..) )
-where
-
-import           Data.Vector.MVector ( MVector(..), MVectorPure(..) )
-import qualified Data.Vector.Unboxed.Mutable.ST as STV
-import           Data.Vector.Unboxed.Unbox ( Unbox )
-
-import GHC.Base   ( RealWorld )
-import GHC.ST     ( ST(..) )
-import GHC.IOBase ( IO(..) )
-
-import Prelude hiding ( length )
-
--- | IO-based mutable vectors
-newtype Vector a = Vector (STV.Vector RealWorld a)
-
-instance Unbox a => MVectorPure Vector a where
-  {-# INLINE length #-}
-  length (Vector v) = length v
-
-  {-# INLINE unsafeSlice #-}
-  unsafeSlice (Vector v) j m = Vector (unsafeSlice v j m)
-
-  {-# INLINE overlaps #-}
-  overlaps (Vector v1) (Vector v2) = overlaps v1 v2
-
-instance Unbox a => MVector Vector IO a where
-  {-# INLINE unsafeNew #-}
-  unsafeNew n = Vector `fmap` stToIO (unsafeNew n)
-
-  {-# INLINE unsafeNewWith #-}
-  unsafeNewWith n x = Vector `fmap` stToIO (unsafeNewWith n x)
-
-  {-# INLINE unsafeRead #-}
-  unsafeRead (Vector v) i = stToIO (unsafeRead v i)
-
-  {-# INLINE unsafeWrite #-}
-  unsafeWrite (Vector v) i x = stToIO (unsafeWrite v i x)
-
-  {-# INLINE clear #-}
-  clear (Vector v) = stToIO (clear v)
-
-stToIO :: ST RealWorld a -> IO a
-stToIO (ST m) = IO m
-
diff --git a/Data/Vector/Unboxed/Mutable/ST.hs b/Data/Vector/Unboxed/Mutable/ST.hs
deleted file mode 100644
--- a/Data/Vector/Unboxed/Mutable/ST.hs
+++ /dev/null
@@ -1,63 +0,0 @@
-{-# LANGUAGE MagicHash, UnboxedTuples, MultiParamTypeClasses, FlexibleInstances, ScopedTypeVariables #-}
-
--- |
--- Module      : Data.Vector.Unboxed.Mutable.ST
--- Copyright   : (c) Roman Leshchinskiy 2008
--- License     : BSD-style
---
--- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
--- Stability   : experimental
--- Portability : non-portable
--- 
--- Mutable unboxed vectors based on 'Unbox' in the ST monad.
---
-
-module Data.Vector.Unboxed.Mutable.ST ( Vector(..) )
-where
-
-import qualified Data.Vector.MVector as MVector
-import           Data.Vector.MVector ( MVector, MVectorPure )
-import           Data.Vector.Unboxed.Unbox
-
-import GHC.Prim ( MutableByteArray#,
-                  newByteArray#, sameMutableByteArray#, (+#) )
-
-import GHC.ST   ( ST(..) )
-
-import GHC.Base ( Int(..) )
-
--- | Mutable unboxed vectors. They live in the 'ST' monad.
-data Vector s a = Vector {-# UNPACK #-} !Int
-                         {-# UNPACK #-} !Int
-                                        (MutableByteArray# s)
-
-instance Unbox a => MVectorPure (Vector s) a where
-  length (Vector _ n _) = n
-  unsafeSlice (Vector i _ arr#) j m = Vector (i+j) m arr#
-
-  {-# INLINE overlaps #-}
-  overlaps (Vector i m arr1#) (Vector j n arr2#)
-    = sameMutableByteArray# arr1# arr2#
-      && (between i j (j+n) || between j i (i+m))
-    where
-      between x y z = x >= y && x < z
-
-
-instance Unbox a => MVector (Vector s) (ST s) a where
-  {-# INLINE unsafeNew #-}
-  unsafeNew (I# n#) = ST (\s# ->
-      case newByteArray# (size# (undefined :: a) n#) s# of
-        (# s2#, arr# #) -> (# s2#, Vector 0 (I# n#) arr# #)
-    )
-
-  {-# INLINE unsafeRead #-}
-  unsafeRead (Vector (I# i#) _ arr#) (I# j#) = ST (read# arr# (i# +# j#))
-
-  {-# INLINE unsafeWrite #-}
-  unsafeWrite (Vector (I# i#) _ arr#) (I# j#) x = ST (\s# ->
-      case write# arr# (i# +# j#) x s# of s2# -> (# s2#, () #)
-    )
-
-  {-# INLINE clear #-}
-  clear _ = return ()
-
diff --git a/Data/Vector/Unboxed/Unbox.hs b/Data/Vector/Unboxed/Unbox.hs
deleted file mode 100644
--- a/Data/Vector/Unboxed/Unbox.hs
+++ /dev/null
@@ -1,85 +0,0 @@
-{-# LANGUAGE MagicHash, UnboxedTuples #-}
-
--- |
--- Module      : Data.Vector.Unboxed.Unbox
--- Copyright   : (c) Roman Leshchinskiy 2008
--- License     : BSD-style
---
--- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
--- Stability   : experimental
--- Portability : non-portable
--- 
--- Primitives for manipulating unboxed arrays
---
-
-module Data.Vector.Unboxed.Unbox (
-  Unbox(..)
-) where
-
-import GHC.Base (
-    Int(..)
-  )
-import GHC.Float (
-    Float(..), Double(..)
-  )
-import GHC.Word (
-    Word(..)
-  )
-
-import GHC.Prim (
-    ByteArray#, MutableByteArray#, State#,
-
-    Int#, indexIntArray#,    readIntArray#,    writeIntArray#,
-          indexWordArray#,   readWordArray#,   writeWordArray#,
-          indexFloatArray#,  readFloatArray#,  writeFloatArray#,
-          indexDoubleArray#, readDoubleArray#, writeDoubleArray#
-  )
-import Data.Array.Base (
-    wORD_SCALE, fLOAT_SCALE, dOUBLE_SCALE
-  )
-
--- | Class of types which can be stored in unboxed arrays
-class Unbox a where
-  -- | Yield the size in bytes of a 'ByteArray#' which can store @n@ elements
-  size#  :: a     -- ^ Dummy type parameter, never evaluated
-         -> Int#  -- ^ Number of elements
-         -> Int#
-
-  -- | Indexing
-  at#    :: ByteArray# -> Int# -> a
-
-  -- | Yield the element at the given position
-  read#  :: MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)
-
-  -- | Store the given element at the given position
-  write# :: MutableByteArray# s -> Int# -> a -> State# s -> State# s
-
-instance Unbox Word where
-  size# _                   = wORD_SCALE
-  at#    arr# i#            = W# (indexWordArray# arr# i#)
-  read#  arr# i# s#         = case readWordArray# arr# i# s# of
-                                (# s1#, n# #) -> (# s1#, W# n# #)
-  write# arr# i# (W# n#) s# = writeWordArray# arr# i# n# s#
-
-
-instance Unbox Int where
-  size#  _                  = wORD_SCALE
-  at#    arr# i#            = I# (indexIntArray# arr# i#)
-  read#  arr# i# s#         = case readIntArray# arr# i# s# of
-                                (# s1#, n# #) -> (# s1#, I# n# #)
-  write# arr# i# (I# n#) s# = writeIntArray# arr# i# n# s#
-
-instance Unbox Float where
-  size#  _                  = fLOAT_SCALE
-  at#    arr# i#            = F# (indexFloatArray# arr# i#)
-  read#  arr# i# s#         = case readFloatArray# arr# i# s# of
-                                (# s1#, x# #) -> (# s1#, F# x# #)
-  write# arr# i# (F# x#) s# = writeFloatArray# arr# i# x# s#
-
-instance Unbox Double where
-  size#  _                  = dOUBLE_SCALE
-  at#    arr# i#            = D# (indexDoubleArray# arr# i#)
-  read#  arr# i# s#         = case readDoubleArray# arr# i# s# of
-                                (# s1#, x# #) -> (# s1#, D# x# #)
-  write# arr# i# (D# x#) s# = writeDoubleArray# arr# i# x# s#
-
diff --git a/include/phases.h b/include/phases.h
--- a/include/phases.h
+++ b/include/phases.h
@@ -1,2 +1,6 @@
-#define INLINE_STREAM INLINE [1]
+#define PHASE_STREAM [1]
+#define PHASE_INNER  [0]
+
+#define INLINE_STREAM INLINE PHASE_STREAM
+#define INLINE_INNER  INLINE PHASE_INNER
 
diff --git a/tests/Boilerplater.hs b/tests/Boilerplater.hs
--- a/tests/Boilerplater.hs
+++ b/tests/Boilerplater.hs
@@ -1,6 +1,6 @@
 module Boilerplater where
 
-import Test.Framework.Providers.QuickCheck
+import Test.Framework.Providers.QuickCheck2
 
 import Language.Haskell.TH
 
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -1,7 +1,10 @@
 module Main (main) where
 
-import Properties (tests)
+import qualified Tests.Vector
+import qualified Tests.Stream
 
 import Test.Framework (defaultMain)
 
-main = defaultMain tests
+main = defaultMain $ Tests.Stream.tests
+                  ++ Tests.Vector.tests
+
diff --git a/tests/Properties.hs b/tests/Properties.hs
deleted file mode 100644
--- a/tests/Properties.hs
+++ /dev/null
@@ -1,235 +0,0 @@
-module Properties (tests) where
-
-import Boilerplater
-import Utilities
-
-import qualified Data.Vector.IVector as V
-import qualified Data.Vector
-import qualified Data.Vector.Unboxed
-import qualified Data.Vector.Fusion.Stream as S
-
-import Test.QuickCheck
-
-import Test.Framework
-import Test.Framework.Providers.QuickCheck
-
-import Text.Show.Functions ()
-import Data.List           (foldl', foldl1', unfoldr, find, findIndex)
-
-#define COMMON_CONTEXT(a, v) \
- VANILLA_CONTEXT(a, v), VECTOR_CONTEXT(a, v)
-
-#define VANILLA_CONTEXT(a, v) \
-  Eq a,     Show a,     Arbitrary a,     Model a a
-
-#define VECTOR_CONTEXT(a, v) \
-  Eq (v a), Show (v a), Arbitrary (v a), Model (v a) [a], V.IVector v a
-
-
--- TODO: implement Vector equivalents of list functions for some of the commented out properties
-
--- TODO: test and implement some of these other Prelude functions:
---  mapM *
---  mapM_ *
---  sequence
---  sequence_
---  sum *
---  product *
---  scanl *
---  scanl1 *
---  scanr *
---  scanr1 *
---  lookup *
---  lines
---  words
---  unlines
---  unwords
--- NB: this is an exhaustive list of all Prelude list functions that make sense for vectors.
--- Ones with *s are the most plausible candidates.
-
--- TODO: add tests for the other extra functions
--- IVector exports still needing tests:
---  copy,
---  slice,
---  (//), update, bpermute,
---  prescanl, prescanl',
---  new,
---  unsafeSlice, unsafeIndex,
---  vlength, vnew
-
--- TODO: test non-IVector stuff?
-
-testSanity :: forall a v. (COMMON_CONTEXT(a, v)) => v a -> [Test]
-testSanity _ = [
-        testProperty "fromList.toList == id" prop_fromList_toList,
-        testProperty "toList.fromList == id" prop_toList_fromList,
-        testProperty "unstream.stream == id" prop_unstream_stream,
-        testProperty "stream.unstream == id" prop_stream_unstream
-    ]
-  where
-    prop_fromList_toList (v :: v a)        = (V.fromList . V.toList)                        v == v
-    prop_toList_fromList (l :: [a])        = ((V.toList :: v a -> [a]) . V.fromList)        l == l
-    prop_unstream_stream (v :: v a)        = (V.unstream . V.stream)                        v == v
-    prop_stream_unstream (s :: S.Stream a) = ((V.stream :: v a -> S.Stream a) . V.unstream) s == s
-
-testPolymorphicFunctions :: forall a v. (COMMON_CONTEXT(a, v)) => v a -> [Test]
-testPolymorphicFunctions _ = $(testProperties [
-        'prop_eq, 'prop_length, 'prop_null, 'prop_reverse,
-        'prop_append, 'prop_concatMap,
-        'prop_empty, 'prop_cons,
-        'prop_head, 'prop_tail, 'prop_init, 'prop_last,
-        'prop_drop, 'prop_dropWhile, 'prop_take, 'prop_takeWhile,
-        'prop_filter, 'prop_map, 'prop_replicate,
-        'prop_zipWith, 'prop_zipWith3,
-        'prop_elem, 'prop_notElem,
-        'prop_foldr, 'prop_foldl, 'prop_foldr1, 'prop_foldl1,
-        'prop_foldl', 'prop_foldl1',
-        'prop_find, 'prop_findIndex,
-        'prop_unfoldr,
-        'prop_singleton, 'prop_snoc
-    ])
-  where
-    -- Prelude
-    prop_eq           = ((==) :: v a -> v a -> Bool)                  `eq2` (==)
-    prop_length       = (V.length :: v a -> Int)                      `eq1` length
-    prop_null         = (V.null :: v a -> Bool)                       `eq1` null
-    prop_reverse      = (V.reverse :: v a -> v a)                     `eq1` reverse
-    prop_append       = ((V.++) :: v a -> v a -> v a)                 `eq2` (++)
-    prop_concatMap    = (V.concatMap :: (a -> v a) -> v a -> v a)     `eq2` concatMap
-    prop_empty        = (V.empty :: v a)                              `eq0` []
-    prop_cons         = (V.cons :: a -> v a -> v a)                   `eq2` (:)
-    --prop_index        = compare (V.!) to (!!)
-    prop_head         = (V.head :: v a -> a)                          `eqNotNull1` head
-    prop_tail         = (V.tail :: v a -> v a)                        `eqNotNull1` tail
-    prop_init         = (V.init :: v a -> v a)                        `eqNotNull1` init
-    prop_last         = (V.last :: v a -> a)                          `eqNotNull1` last
-    prop_drop         = (V.drop :: Int -> v a -> v a)                 `eq2` drop
-    prop_dropWhile    = (V.dropWhile :: (a -> Bool) -> v a -> v a)    `eq2` dropWhile
-    prop_take         = (V.take :: Int -> v a -> v a)                 `eq2` take
-    prop_takeWhile    = (V.takeWhile :: (a -> Bool) -> v a -> v a)    `eq2` takeWhile
-    prop_filter       = (V.filter :: (a -> Bool) -> v a -> v a)       `eq2` filter
-    prop_map          = (V.map :: (a -> a) -> v a -> v a)             `eq2` map
-    prop_replicate    = (V.replicate :: Int -> a -> v a)              `eq2` replicate
-    prop_zipWith      = (V.zipWith :: (a -> a -> a) -> v a -> v a -> v a) `eq3` zipWith
-    prop_zipWith3     = (V.zipWith3 :: (a -> a -> a -> a) -> v a -> v a -> v a -> v a) `eq4` zipWith3
-    --prop_span         = (V.span :: (a -> Bool) -> v a -> (v a, v a))  `eq2` span
-    --prop_break        = (V.break :: (a -> Bool) -> v a -> (v a, v a)) `eq2` break
-    --prop_splitAt      = (V.splitAt :: Int -> v a -> (v a, v a))       `eq2` splitAt
-    prop_elem         = (V.elem :: a -> v a -> Bool)                  `eq2` elem
-    prop_notElem      = (V.notElem :: a -> v a -> Bool)               `eq2` notElem
-    prop_foldr        = (V.foldr :: (a -> a -> a) -> a -> v a -> a)   `eq3` foldr
-    prop_foldl        = (V.foldl :: (a -> a -> a) -> a -> v a -> a)   `eq3` foldl
-    prop_foldr1       = (V.foldr1 :: (a -> a -> a) -> v a -> a)       `eqNotNull2` foldr1
-    prop_foldl1       = (V.foldl1 :: (a -> a -> a) -> v a -> a)       `eqNotNull2` foldl1
-    --prop_all          = (V.all :: (a -> Bool) -> v a -> Bool)         `eq2` all
-    --prop_any          = (V.any :: (a -> Bool) -> v a -> Bool)         `eq2` any
-
-    -- Data.List
-    prop_foldl'       = (V.foldl' :: (a -> a -> a) -> a -> v a -> a)     `eq3` foldl'
-    prop_foldl1'      = (V.foldl1' :: (a -> a -> a) -> v a -> a)         `eqNotNull2` foldl1'
-    prop_find         = (V.find :: (a -> Bool) -> v a -> Maybe a)        `eq2` find
-    prop_findIndex    = (V.findIndex :: (a -> Bool) -> v a -> Maybe Int) `eq2` findIndex
-    --prop_findIndices  = V.findIndices `eq2` (findIndices :: (a -> Bool) -> v a -> v Int)
-    --prop_isPrefixOf   = V.isPrefixOf  `eq2` (isPrefixOf  :: v a -> v a -> Bool)
-    --prop_elemIndex    = V.elemIndex   `eq2` (elemIndex   :: a -> v a -> Maybe Int)
-    --prop_elemIndices  = V.elemIndices `eq2` (elemIndices :: a -> v a -> v Int)
-    --
-    --prop_mapAccumL  = eq3
-    --    (V.mapAccumL :: (X -> W -> (X,W)) -> X -> B   -> (X, B))
-    --    (  mapAccumL :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))
-    -- 
-    --prop_mapAccumR  = eq3
-    --    (V.mapAccumR :: (X -> W -> (X,W)) -> X -> B   -> (X, B))
-    --    (  mapAccumR :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))
-
-    -- Because the vectors are strict, we need to be totally sure that the unfold eventually terminates. This
-    -- is achieved by injecting our own bit of state into the unfold - the maximum number of unfolds allowed.
-    limitUnfolds f (theirs, ours) | ours >= 0
-                                  , Just (out, theirs') <- f theirs = Just (out, (theirs', ours - 1))
-                                  | otherwise                       = Nothing
-    prop_unfoldr      = ((\n f a -> V.unfoldr (limitUnfolds f) (a, n)) :: Int -> ((Int, Int) -> Maybe (a, (Int, Int))) -> (Int, Int) -> v a)
-                        `eq3` (\n f a -> unfoldr (limitUnfolds f) (a, n))
-
-    -- Extras
-    singleton x = [x]
-    prop_singleton = (V.singleton :: a -> v a) `eq1` singleton
-    
-    snoc xs x = xs ++ [x]
-    prop_snoc = (V.snoc :: v a -> a -> v a) `eq2` snoc
-
-testTuplyFunctions:: forall a v. (COMMON_CONTEXT(a, v), VECTOR_CONTEXT((a, a), v), VECTOR_CONTEXT((a, a, a), v)) => v a -> [Test]
-testTuplyFunctions _ = $(testProperties ['prop_zip, 'prop_zip3, 'prop_unzip, 'prop_unzip3])
-  where
-    prop_zip          = (V.zip :: v a -> v a -> v (a, a))             `eq2` zip
-    prop_zip3         = (V.zip3 :: v a -> v a -> v a -> v (a, a, a))  `eq3` zip3
-    prop_unzip        = (V.unzip :: v (a, a) -> (v a, v a))           `eq1` unzip
-    prop_unzip3       = (V.unzip3 :: v (a, a, a) -> (v a, v a, v a))  `eq1` unzip3
-
-testOrdFunctions :: forall a v. (COMMON_CONTEXT(a, v), Ord a, Ord (v a)) => v a -> [Test]
-testOrdFunctions _ = $(testProperties ['prop_compare, 'prop_maximum, 'prop_minimum])
-  where
-    prop_compare      = (compare :: v a -> v a -> Ordering) `eq2` compare
-    prop_maximum      = (V.maximum :: v a -> a)             `eqNotNull1` maximum
-    prop_minimum      = (V.minimum :: v a -> a)             `eqNotNull1` minimum
-
-testEnumFunctions :: forall a v. (COMMON_CONTEXT(a, v), Enum a) => v a -> [Test]
-testEnumFunctions _ = $(testProperties ['prop_enumFromTo, 'prop_enumFromThenTo])
-  where
-    prop_enumFromTo     =                                        (V.enumFromTo :: a -> a -> v a)          `eq2` enumFromTo
-    prop_enumFromThenTo = \i j n -> fromEnum i < fromEnum j ==> ((V.enumFromThenTo :: a -> a -> a -> v a) `eq3` enumFromThenTo) i j n
-
-testBoolFunctions :: forall v. (COMMON_CONTEXT(Bool, v)) => v Bool -> [Test]
-testBoolFunctions _ = $(testProperties ['prop_and, 'prop_or])
-  where
-    prop_and          = (V.and :: v Bool -> Bool) `eq1` and
-    prop_or           = (V.or :: v Bool -> Bool)  `eq1` or
-
-testNumFunctions :: forall a v. (COMMON_CONTEXT(a, v), Num a) => v a -> [Test]
-testNumFunctions _ = $(testProperties ['prop_sum, 'prop_product])
-  where
-    prop_sum          = (V.sum :: v a -> a)     `eq1` sum
-    prop_product      = (V.product :: v a -> a) `eq1` product
-
-testNestedVectorFunctions :: forall a v. (COMMON_CONTEXT(a, v)) => v a -> [Test]
-testNestedVectorFunctions _ = $(testProperties [])
-  where
-    -- Prelude
-    --prop_concat       = (V.concat :: [v a] -> v a)                    `eq1` concat
-    
-    -- Data.List
-    --prop_transpose    = V.transpose   `eq1` (transpose   :: [v a] -> [v a])
-    --prop_group        = V.group       `eq1` (group       :: v a -> [v a])
-    --prop_inits        = V.inits       `eq1` (inits       :: v a -> [v a])
-    --prop_tails        = V.tails       `eq1` (tails       :: v a -> [v a])
-
-
-testGeneralBoxedVector dummy = concatMap ($ dummy) [
-        testSanity,
-        testPolymorphicFunctions,
-        testOrdFunctions,
-        testEnumFunctions,
-        testTuplyFunctions,
-        testNestedVectorFunctions
-    ]
-
-testBoolBoxedVector dummy = testGeneralBoxedVector dummy ++ testBoolFunctions dummy
-testNumericBoxedVector dummy = testGeneralBoxedVector dummy ++ testNumFunctions dummy
-
-testGeneralUnboxedVector dummy = concatMap ($ dummy) [
-        testSanity,
-        testPolymorphicFunctions,
-        testOrdFunctions,
-        testEnumFunctions
-    ]
-
-testBoolUnboxedVector dummy = testGeneralUnboxedVector dummy ++ testBoolFunctions dummy
-testNumericUnboxedVector dummy = testGeneralUnboxedVector dummy ++ testNumFunctions dummy
-
-tests = [
-        testGroup "Data.Vector.Vector (Bool)"           (testBoolBoxedVector      (undefined :: Data.Vector.Vector Bool)),
-        testGroup "Data.Vector.Vector (Int)"            (testNumericBoxedVector   (undefined :: Data.Vector.Vector Int)),
-        testGroup "Data.Vector.Unboxed.Vector (Bool)"   (testBoolUnboxedVector    (undefined :: Data.Vector.Unboxed.Vector Bool)),
-        testGroup "Data.Vector.Unboxed.Vector (Int)"    (testNumericUnboxedVector (undefined :: Data.Vector.Unboxed.Vector Int)),
-        testGroup "Data.Vector.Unboxed.Vector (Float)"  (testNumericUnboxedVector (undefined :: Data.Vector.Unboxed.Vector Float)),
-        testGroup "Data.Vector.Unboxed.Vector (Double)" (testNumericUnboxedVector (undefined :: Data.Vector.Unboxed.Vector Double))
-    ]
diff --git a/tests/Tests/Stream.hs b/tests/Tests/Stream.hs
new file mode 100644
--- /dev/null
+++ b/tests/Tests/Stream.hs
@@ -0,0 +1,163 @@
+module Tests.Stream ( tests ) where
+
+import Boilerplater
+import Utilities
+
+import qualified Data.Vector.Fusion.Stream as S
+
+import Test.QuickCheck
+
+import Test.Framework
+import Test.Framework.Providers.QuickCheck2
+
+import Text.Show.Functions ()
+import Data.List           (foldl', foldl1', unfoldr, find, findIndex)
+import System.Random       (Random)
+
+#define COMMON_CONTEXT(a) \
+ VANILLA_CONTEXT(a)
+
+#define VANILLA_CONTEXT(a) \
+  Eq a,     Show a,     Arbitrary a,     CoArbitrary a,     TestData a,     Model a ~ a,        EqTest a ~ Property
+
+testSanity :: forall a. (COMMON_CONTEXT(a)) => S.Stream a -> [Test]
+testSanity _ = [
+        testProperty "fromList.toList == id" prop_fromList_toList,
+        testProperty "toList.fromList == id" prop_toList_fromList
+    ]
+  where
+    prop_fromList_toList :: P (S.Stream a -> S.Stream a)
+        = (S.fromList . S.toList) `eq` id
+    prop_toList_fromList :: P ([a] -> [a])
+        = (S.toList . (S.fromList :: [a] -> S.Stream a)) `eq` id
+
+testPolymorphicFunctions :: forall a. (COMMON_CONTEXT(a)) => S.Stream a -> [Test]
+testPolymorphicFunctions _ = $(testProperties [
+        'prop_eq,
+
+        'prop_length, 'prop_null,
+
+        'prop_empty, 'prop_singleton, 'prop_replicate,
+        'prop_cons, 'prop_snoc, 'prop_append,
+
+        'prop_head, 'prop_last, 'prop_index,
+
+        'prop_extract, 'prop_init, 'prop_tail, 'prop_take, 'prop_drop,
+
+        'prop_map, 'prop_zipWith, 'prop_zipWith3,
+        'prop_filter, 'prop_takeWhile, 'prop_dropWhile,
+
+        'prop_elem, 'prop_notElem,
+        'prop_find, 'prop_findIndex,
+
+        'prop_foldl, 'prop_foldl1, 'prop_foldl', 'prop_foldl1',
+        'prop_foldr, 'prop_foldr1,
+
+        'prop_prescanl, 'prop_prescanl',
+        'prop_postscanl, 'prop_postscanl',
+        'prop_scanl, 'prop_scanl', 'prop_scanl1, 'prop_scanl1',
+
+        'prop_concatMap,
+        'prop_unfoldr
+    ])
+  where
+    -- Prelude
+    prop_eq :: P (S.Stream a -> S.Stream a -> Bool) = (==) `eq` (==)
+
+    prop_length :: P (S.Stream a -> Int)     = S.length `eq` length
+    prop_null   :: P (S.Stream a -> Bool)    = S.null `eq` null
+    prop_empty  :: P (S.Stream a)            = S.empty `eq` []
+    prop_singleton :: P (a -> S.Stream a)    = S.singleton `eq` singleton
+    prop_replicate :: P (Int -> a -> S.Stream a)
+              = (\n _ -> n < 1000) ===> S.replicate `eq` replicate
+    prop_cons      :: P (a -> S.Stream a -> S.Stream a) = S.cons `eq` (:)
+    prop_snoc      :: P (S.Stream a -> a -> S.Stream a) = S.snoc `eq` snoc
+    prop_append    :: P (S.Stream a -> S.Stream a -> S.Stream a) = (S.++) `eq` (++)
+
+    prop_head      :: P (S.Stream a -> a) = not . S.null ===> S.head `eq` head
+    prop_last      :: P (S.Stream a -> a) = not . S.null ===> S.last `eq` last
+    prop_index        = \xs ->
+                        not (S.null xs) ==>
+                        forAll (choose (0, S.length xs-1)) $ \i ->
+                        unP prop xs i
+      where
+        prop :: P (S.Stream a -> Int -> a) = (S.!!) `eq` (!!)
+
+    prop_extract      = \xs ->
+                        forAll (choose (0, S.length xs))     $ \i ->
+                        forAll (choose (0, S.length xs - i)) $ \n ->
+                        unP prop xs i n
+      where
+        prop :: P (S.Stream a -> Int -> Int -> S.Stream a) = S.extract `eq` slice
+
+    prop_tail :: P (S.Stream a -> S.Stream a) = not . S.null ===> S.tail `eq` tail
+    prop_init :: P (S.Stream a -> S.Stream a) = not . S.null ===> S.init `eq` init
+    prop_take :: P (Int -> S.Stream a -> S.Stream a) = S.take `eq` take
+    prop_drop :: P (Int -> S.Stream a -> S.Stream a) = S.drop `eq` drop
+
+    prop_map :: P ((a -> a) -> S.Stream a -> S.Stream a) = S.map `eq` map
+    prop_zipWith :: P ((a -> a -> a) -> S.Stream a -> S.Stream a -> S.Stream a) = S.zipWith `eq` zipWith
+    prop_zipWith3 :: P ((a -> a -> a -> a) -> S.Stream a -> S.Stream a -> S.Stream a -> S.Stream a)
+             = S.zipWith3 `eq` zipWith3
+
+    prop_filter :: P ((a -> Bool) -> S.Stream a -> S.Stream a) = S.filter `eq` filter
+    prop_takeWhile :: P ((a -> Bool) -> S.Stream a -> S.Stream a) = S.takeWhile `eq` takeWhile
+    prop_dropWhile :: P ((a -> Bool) -> S.Stream a -> S.Stream a) = S.dropWhile `eq` dropWhile
+
+    prop_elem    :: P (a -> S.Stream a -> Bool) = S.elem `eq` elem
+    prop_notElem :: P (a -> S.Stream a -> Bool) = S.notElem `eq` notElem
+    prop_find    :: P ((a -> Bool) -> S.Stream a -> Maybe a) = S.find `eq` find
+    prop_findIndex :: P ((a -> Bool) -> S.Stream a -> Maybe Int)
+      = S.findIndex `eq` findIndex
+
+    prop_foldl :: P ((a -> a -> a) -> a -> S.Stream a -> a) = S.foldl `eq` foldl
+    prop_foldl1 :: P ((a -> a -> a) -> S.Stream a -> a)     = notNullS2 ===>
+                        S.foldl1 `eq` foldl1
+    prop_foldl' :: P ((a -> a -> a) -> a -> S.Stream a -> a) = S.foldl' `eq` foldl'
+    prop_foldl1' :: P ((a -> a -> a) -> S.Stream a -> a)     = notNullS2 ===>
+                        S.foldl1' `eq` foldl1'
+    prop_foldr :: P ((a -> a -> a) -> a -> S.Stream a -> a) = S.foldr `eq` foldr
+    prop_foldr1 :: P ((a -> a -> a) -> S.Stream a -> a)     = notNullS2 ===>
+                        S.foldr1 `eq` foldr1
+
+    prop_prescanl :: P ((a -> a -> a) -> a -> S.Stream a -> S.Stream a)
+                = S.prescanl `eq` prescanl
+    prop_prescanl' :: P ((a -> a -> a) -> a -> S.Stream a -> S.Stream a)
+                = S.prescanl' `eq` prescanl
+    prop_postscanl :: P ((a -> a -> a) -> a -> S.Stream a -> S.Stream a)
+                = S.postscanl `eq` postscanl
+    prop_postscanl' :: P ((a -> a -> a) -> a -> S.Stream a -> S.Stream a)
+                = S.postscanl' `eq` postscanl
+    prop_scanl :: P ((a -> a -> a) -> a -> S.Stream a -> S.Stream a)
+                = S.scanl `eq` scanl
+    prop_scanl' :: P ((a -> a -> a) -> a -> S.Stream a -> S.Stream a)
+               = S.scanl' `eq` scanl
+    prop_scanl1 :: P ((a -> a -> a) -> S.Stream a -> S.Stream a) = notNullS2 ===>
+                 S.scanl1 `eq` scanl1
+    prop_scanl1' :: P ((a -> a -> a) -> S.Stream a -> S.Stream a) = notNullS2 ===>
+                 S.scanl1' `eq` scanl1
+ 
+    prop_concatMap    = forAll arbitrary $ \xs ->
+                        forAll (sized (\n -> resize (n `div` S.length xs) arbitrary)) $ \f -> unP prop f xs
+      where
+        prop :: P ((a -> S.Stream a) -> S.Stream a -> S.Stream a) = S.concatMap `eq` concatMap
+
+    limitUnfolds f (theirs, ours) | ours >= 0
+                                  , Just (out, theirs') <- f theirs = Just (out, (theirs', ours - 1))
+                                  | otherwise                       = Nothing
+    prop_unfoldr :: P (Int -> (Int -> Maybe (a,Int)) -> Int -> S.Stream a)
+         = (\n f a -> S.unfoldr (limitUnfolds f) (a, n))
+           `eq` (\n f a -> unfoldr (limitUnfolds f) (a, n))
+
+testBoolFunctions :: [Test]
+testBoolFunctions = $(testProperties ['prop_and, 'prop_or])
+  where
+    prop_and :: P (S.Stream Bool -> Bool) = S.and `eq` and
+    prop_or  :: P (S.Stream Bool -> Bool) = S.or `eq` or
+
+testStreamFunctions = testSanity (undefined :: S.Stream Int)
+                      ++ testPolymorphicFunctions (undefined :: S.Stream Int)
+                      ++ testBoolFunctions
+
+tests = [ testGroup "Data.Vector.Fusion.Stream" testStreamFunctions ]
+
diff --git a/tests/Tests/Vector.hs b/tests/Tests/Vector.hs
new file mode 100644
--- /dev/null
+++ b/tests/Tests/Vector.hs
@@ -0,0 +1,342 @@
+module Tests.Vector (tests) where
+
+import Boilerplater
+import Utilities
+
+import qualified Data.Vector.Generic as V
+import qualified Data.Vector
+import qualified Data.Vector.Primitive
+import qualified Data.Vector.Storable
+import qualified Data.Vector.Fusion.Stream as S
+
+import Test.QuickCheck
+
+import Test.Framework
+import Test.Framework.Providers.QuickCheck2
+
+import Text.Show.Functions ()
+import Data.List           (foldl', foldl1', unfoldr, find, findIndex)
+import System.Random       (Random)
+
+#define COMMON_CONTEXT(a, v) \
+ VANILLA_CONTEXT(a, v), VECTOR_CONTEXT(a, v)
+
+#define VANILLA_CONTEXT(a, v) \
+  Eq a,     Show a,     Arbitrary a,     CoArbitrary a,     TestData a,     Model a ~ a,        EqTest a ~ Property
+
+#define VECTOR_CONTEXT(a, v) \
+  Eq (v a), Show (v a), Arbitrary (v a), CoArbitrary (v a), TestData (v a), Model (v a) ~ [a],  EqTest (v a) ~ Property, V.Vector v a
+
+-- TODO: implement Vector equivalents of list functions for some of the commented out properties
+
+-- TODO: test and implement some of these other Prelude functions:
+--  mapM *
+--  mapM_ *
+--  sequence
+--  sequence_
+--  sum *
+--  product *
+--  scanl *
+--  scanl1 *
+--  scanr *
+--  scanr1 *
+--  lookup *
+--  lines
+--  words
+--  unlines
+--  unwords
+-- NB: this is an exhaustive list of all Prelude list functions that make sense for vectors.
+-- Ones with *s are the most plausible candidates.
+
+-- TODO: add tests for the other extra functions
+-- IVector exports still needing tests:
+--  copy,
+--  slice,
+--  (//), update, bpermute,
+--  prescanl, prescanl',
+--  new,
+--  unsafeSlice, unsafeIndex,
+--  vlength, vnew
+
+-- TODO: test non-IVector stuff?
+
+testSanity :: forall a v. (COMMON_CONTEXT(a, v)) => v a -> [Test]
+testSanity _ = [
+        testProperty "fromList.toList == id" prop_fromList_toList,
+        testProperty "toList.fromList == id" prop_toList_fromList,
+        testProperty "unstream.stream == id" prop_unstream_stream,
+        testProperty "stream.unstream == id" prop_stream_unstream
+    ]
+  where
+    prop_fromList_toList (v :: v a)        = (V.fromList . V.toList)                        v == v
+    prop_toList_fromList (l :: [a])        = ((V.toList :: v a -> [a]) . V.fromList)        l == l
+    prop_unstream_stream (v :: v a)        = (V.unstream . V.stream)                        v == v
+    prop_stream_unstream (s :: S.Stream a) = ((V.stream :: v a -> S.Stream a) . V.unstream) s == s
+
+testPolymorphicFunctions :: forall a v. (COMMON_CONTEXT(a, v), VECTOR_CONTEXT(Int, v)) => v a -> [Test]
+testPolymorphicFunctions _ = $(testProperties [
+        'prop_eq,
+
+        'prop_length, 'prop_null,
+
+        'prop_empty, 'prop_singleton, 'prop_replicate,
+        'prop_cons, 'prop_snoc, 'prop_append, 'prop_copy,
+
+        'prop_head, 'prop_last, 'prop_index,
+
+        'prop_slice, 'prop_init, 'prop_tail, 'prop_take, 'prop_drop,
+
+        'prop_accum, 'prop_write, 'prop_backpermute, 'prop_reverse,
+
+        'prop_map, 'prop_zipWith, 'prop_zipWith3,
+        'prop_filter, 'prop_takeWhile, 'prop_dropWhile,
+
+        'prop_elem, 'prop_notElem,
+        'prop_find, 'prop_findIndex,
+
+        'prop_foldl, 'prop_foldl1, 'prop_foldl', 'prop_foldl1',
+        'prop_foldr, 'prop_foldr1,
+
+        'prop_prescanl, 'prop_prescanl',
+        'prop_postscanl, 'prop_postscanl',
+        'prop_scanl, 'prop_scanl', 'prop_scanl1, 'prop_scanl1',
+
+        'prop_concatMap,
+        'prop_unfoldr
+    ])
+  where
+    -- Prelude
+    prop_eq :: P (v a -> v a -> Bool) = (==) `eq` (==)
+
+    prop_length :: P (v a -> Int)     = V.length `eq` length
+    prop_null   :: P (v a -> Bool)    = V.null `eq` null
+
+    prop_empty  :: P (v a)            = V.empty `eq` []
+    prop_singleton :: P (a -> v a)    = V.singleton `eq` singleton
+    prop_replicate :: P (Int -> a -> v a)
+              = (\n _ -> n < 1000) ===> V.replicate `eq` replicate
+    prop_cons      :: P (a -> v a -> v a) = V.cons `eq` (:)
+    prop_snoc      :: P (v a -> a -> v a) = V.snoc `eq` snoc
+    prop_append    :: P (v a -> v a -> v a) = (V.++) `eq` (++)
+    prop_copy      :: P (v a -> v a)        = V.copy `eq` id
+
+    prop_head      :: P (v a -> a) = not . V.null ===> V.head `eq` head
+    prop_last      :: P (v a -> a) = not . V.null ===> V.last `eq` last
+    prop_index        = \xs ->
+                        not (V.null xs) ==>
+                        forAll (choose (0, V.length xs-1)) $ \i ->
+                        unP prop xs i
+      where
+        prop :: P (v a -> Int -> a) = (V.!) `eq` (!!)
+
+    prop_slice        = \xs ->
+                        forAll (choose (0, V.length xs))     $ \i ->
+                        forAll (choose (0, V.length xs - i)) $ \n ->
+                        unP prop xs i n
+      where
+        prop :: P (v a -> Int -> Int -> v a) = V.slice `eq` slice
+
+    prop_tail :: P (v a -> v a) = not . V.null ===> V.tail `eq` tail
+    prop_init :: P (v a -> v a) = not . V.null ===> V.init `eq` init
+    prop_take :: P (Int -> v a -> v a) = V.take `eq` take
+    prop_drop :: P (Int -> v a -> v a) = V.drop `eq` drop
+
+    prop_accum = \f xs ->
+                 forAll (index_value_pairs (V.length xs)) $ \ps ->
+                 unP prop f xs ps
+      where
+        prop :: P ((a -> a -> a) -> v a -> [(Int,a)] -> v a)
+          = V.accum `eq` accum
+
+    prop_write        = \xs ->
+                        forAll (index_value_pairs (V.length xs)) $ \ps ->
+                        unP prop xs ps
+      where
+        prop :: P (v a -> [(Int,a)] -> v a) = (V.//) `eq` (//)
+
+    prop_backpermute  = \xs ->
+                        forAll (indices (V.length xs)) $ \is ->
+                        unP prop xs (V.fromList is)
+      where
+        prop :: P (v a -> v Int -> v a) = V.backpermute `eq` backpermute
+
+    prop_reverse :: P (v a -> v a) = V.reverse `eq` reverse
+
+    prop_map :: P ((a -> a) -> v a -> v a) = V.map `eq` map
+    prop_zipWith :: P ((a -> a -> a) -> v a -> v a -> v a) = V.zipWith `eq` zipWith
+    prop_zipWith3 :: P ((a -> a -> a -> a) -> v a -> v a -> v a -> v a)
+             = V.zipWith3 `eq` zipWith3
+
+    prop_filter :: P ((a -> Bool) -> v a -> v a) = V.filter `eq` filter
+    prop_takeWhile :: P ((a -> Bool) -> v a -> v a) = V.takeWhile `eq` takeWhile
+    prop_dropWhile :: P ((a -> Bool) -> v a -> v a) = V.dropWhile `eq` dropWhile
+
+    prop_elem    :: P (a -> v a -> Bool) = V.elem `eq` elem
+    prop_notElem :: P (a -> v a -> Bool) = V.notElem `eq` notElem
+    prop_find    :: P ((a -> Bool) -> v a -> Maybe a) = V.find `eq` find
+    prop_findIndex :: P ((a -> Bool) -> v a -> Maybe Int)
+      = V.findIndex `eq` findIndex
+
+    prop_foldl :: P ((a -> a -> a) -> a -> v a -> a) = V.foldl `eq` foldl
+    prop_foldl1 :: P ((a -> a -> a) -> v a -> a)     = notNull2 ===>
+                        V.foldl1 `eq` foldl1
+    prop_foldl' :: P ((a -> a -> a) -> a -> v a -> a) = V.foldl' `eq` foldl'
+    prop_foldl1' :: P ((a -> a -> a) -> v a -> a)     = notNull2 ===>
+                        V.foldl1' `eq` foldl1'
+    prop_foldr :: P ((a -> a -> a) -> a -> v a -> a) = V.foldr `eq` foldr
+    prop_foldr1 :: P ((a -> a -> a) -> v a -> a)     = notNull2 ===>
+                        V.foldr1 `eq` foldr1
+
+    prop_prescanl :: P ((a -> a -> a) -> a -> v a -> v a)
+                = V.prescanl `eq` prescanl
+    prop_prescanl' :: P ((a -> a -> a) -> a -> v a -> v a)
+                = V.prescanl' `eq` prescanl
+    prop_postscanl :: P ((a -> a -> a) -> a -> v a -> v a)
+                = V.postscanl `eq` postscanl
+    prop_postscanl' :: P ((a -> a -> a) -> a -> v a -> v a)
+                = V.postscanl' `eq` postscanl
+    prop_scanl :: P ((a -> a -> a) -> a -> v a -> v a)
+                = V.scanl `eq` scanl
+    prop_scanl' :: P ((a -> a -> a) -> a -> v a -> v a)
+               = V.scanl' `eq` scanl
+    prop_scanl1 :: P ((a -> a -> a) -> v a -> v a) = notNull2 ===>
+                 V.scanl1 `eq` scanl1
+    prop_scanl1' :: P ((a -> a -> a) -> v a -> v a) = notNull2 ===>
+                 V.scanl1' `eq` scanl1
+ 
+    prop_concatMap    = forAll arbitrary $ \xs ->
+                        forAll (sized (\n -> resize (n `div` V.length xs) arbitrary)) $ \f -> unP prop f xs
+      where
+        prop :: P ((a -> v a) -> v a -> v a) = V.concatMap `eq` concatMap
+
+    --prop_span         = (V.span :: (a -> Bool) -> v a -> (v a, v a))  `eq2` span
+    --prop_break        = (V.break :: (a -> Bool) -> v a -> (v a, v a)) `eq2` break
+    --prop_splitAt      = (V.splitAt :: Int -> v a -> (v a, v a))       `eq2` splitAt
+    --prop_all          = (V.all :: (a -> Bool) -> v a -> Bool)         `eq2` all
+    --prop_any          = (V.any :: (a -> Bool) -> v a -> Bool)         `eq2` any
+
+    -- Data.List
+    --prop_findIndices  = V.findIndices `eq2` (findIndices :: (a -> Bool) -> v a -> v Int)
+    --prop_isPrefixOf   = V.isPrefixOf  `eq2` (isPrefixOf  :: v a -> v a -> Bool)
+    --prop_elemIndex    = V.elemIndex   `eq2` (elemIndex   :: a -> v a -> Maybe Int)
+    --prop_elemIndices  = V.elemIndices `eq2` (elemIndices :: a -> v a -> v Int)
+    --
+    --prop_mapAccumL  = eq3
+    --    (V.mapAccumL :: (X -> W -> (X,W)) -> X -> B   -> (X, B))
+    --    (  mapAccumL :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))
+    -- 
+    --prop_mapAccumR  = eq3
+    --    (V.mapAccumR :: (X -> W -> (X,W)) -> X -> B   -> (X, B))
+    --    (  mapAccumR :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))
+
+    -- Because the vectors are strict, we need to be totally sure that the unfold eventually terminates. This
+    -- is achieved by injecting our own bit of state into the unfold - the maximum number of unfolds allowed.
+    limitUnfolds f (theirs, ours) | ours >= 0
+                                  , Just (out, theirs') <- f theirs = Just (out, (theirs', ours - 1))
+                                  | otherwise                       = Nothing
+    prop_unfoldr :: P (Int -> (Int -> Maybe (a,Int)) -> Int -> v a)
+         = (\n f a -> V.unfoldr (limitUnfolds f) (a, n))
+           `eq` (\n f a -> unfoldr (limitUnfolds f) (a, n))
+
+
+testTuplyFunctions:: forall a v. (COMMON_CONTEXT(a, v), VECTOR_CONTEXT((a, a), v), VECTOR_CONTEXT((a, a, a), v)) => v a -> [Test]
+testTuplyFunctions _ = $(testProperties ['prop_zip, 'prop_zip3, 'prop_unzip, 'prop_unzip3])
+  where
+    prop_zip    :: P (v a -> v a -> v (a, a))           = V.zip `eq` zip
+    prop_zip3   :: P (v a -> v a -> v a -> v (a, a, a)) = V.zip3 `eq` zip3
+    prop_unzip  :: P (v (a, a) -> (v a, v a))           = V.unzip `eq` unzip
+    prop_unzip3 :: P (v (a, a, a) -> (v a, v a, v a))   = V.unzip3 `eq` unzip3
+
+testOrdFunctions :: forall a v. (COMMON_CONTEXT(a, v), Ord a, Ord (v a)) => v a -> [Test]
+testOrdFunctions _ = $(testProperties ['prop_compare, 'prop_maximum, 'prop_minimum])
+  where
+    prop_compare :: P (v a -> v a -> Ordering) = compare `eq` compare
+    prop_maximum :: P (v a -> a) = not . V.null ===> V.maximum `eq` maximum
+    prop_minimum :: P (v a -> a) = not . V.null ===> V.minimum `eq` minimum
+
+testEnumFunctions :: forall a v. (COMMON_CONTEXT(a, v), Enum a, Ord a, Num a, Random a) => v a -> [Test]
+testEnumFunctions _ = $(testProperties ['prop_enumFromTo, 'prop_enumFromThenTo])
+  where
+    prop_enumFromTo = \m ->
+                      forAll (choose (-2,100)) $ \n ->
+                      unP prop m (m+n)
+      where
+        prop  :: P (a -> a -> v a) = V.enumFromTo `eq` enumFromTo
+
+    prop_enumFromThenTo = \i j ->
+                          j /= i ==>
+                          forAll (choose (ks i j)) $ \k ->
+                          unP prop i j k
+      where
+        prop :: P (a -> a -> a -> v a) = V.enumFromThenTo `eq` enumFromThenTo
+
+        ks i j | j < i     = (i-d*100, i+d*2)
+               | otherwise = (i-d*2, i+d*100)
+          where
+            d = abs (j-i)
+                          
+testBoolFunctions :: forall v. (COMMON_CONTEXT(Bool, v)) => v Bool -> [Test]
+testBoolFunctions _ = $(testProperties ['prop_and, 'prop_or])
+  where
+    prop_and :: P (v Bool -> Bool) = V.and `eq` and
+    prop_or  :: P (v Bool -> Bool) = V.or `eq` or
+
+testNumFunctions :: forall a v. (COMMON_CONTEXT(a, v), Num a) => v a -> [Test]
+testNumFunctions _ = $(testProperties ['prop_sum, 'prop_product])
+  where
+    prop_sum     :: P (v a -> a) = V.sum `eq` sum
+    prop_product :: P (v a -> a) = V.product `eq` product
+
+testNestedVectorFunctions :: forall a v. (COMMON_CONTEXT(a, v)) => v a -> [Test]
+testNestedVectorFunctions _ = $(testProperties [])
+  where
+    -- Prelude
+    --prop_concat       = (V.concat :: [v a] -> v a)                    `eq1` concat
+    
+    -- Data.List
+    --prop_transpose    = V.transpose   `eq1` (transpose   :: [v a] -> [v a])
+    --prop_group        = V.group       `eq1` (group       :: v a -> [v a])
+    --prop_inits        = V.inits       `eq1` (inits       :: v a -> [v a])
+    --prop_tails        = V.tails       `eq1` (tails       :: v a -> [v a])
+
+
+testGeneralBoxedVector dummy = concatMap ($ dummy) [
+        testSanity,
+        testPolymorphicFunctions,
+        testOrdFunctions,
+        testTuplyFunctions,
+        testNestedVectorFunctions
+    ]
+
+testBoolBoxedVector dummy = testGeneralBoxedVector dummy ++ testBoolFunctions dummy
+testNumericBoxedVector dummy = testGeneralBoxedVector dummy ++ testNumFunctions dummy ++ testEnumFunctions dummy
+
+testGeneralPrimitiveVector dummy = concatMap ($ dummy) [
+        testSanity,
+        testPolymorphicFunctions,
+        testOrdFunctions
+    ]
+
+testGeneralStorableVector dummy = concatMap ($ dummy) [
+        testSanity,
+        testPolymorphicFunctions,
+        testOrdFunctions
+    ]
+
+testBoolPrimitiveVector dummy = testGeneralPrimitiveVector dummy ++ testBoolFunctions dummy
+testNumericPrimitiveVector dummy = testGeneralPrimitiveVector dummy ++ testNumFunctions dummy ++ testEnumFunctions dummy
+testNumericStorableVector dummy = testGeneralStorableVector dummy ++ testNumFunctions dummy ++ testEnumFunctions dummy
+
+tests = [
+        testGroup "Data.Vector.Vector (Bool)"           (testBoolBoxedVector      (undefined :: Data.Vector.Vector Bool)),
+        testGroup "Data.Vector.Vector (Int)"            (testNumericBoxedVector   (undefined :: Data.Vector.Vector Int)),
+
+        testGroup "Data.Vector.Primitive.Vector (Int)"    (testNumericPrimitiveVector (undefined :: Data.Vector.Primitive.Vector Int)),
+        testGroup "Data.Vector.Primitive.Vector (Float)"  (testNumericPrimitiveVector (undefined :: Data.Vector.Primitive.Vector Float)),
+        testGroup "Data.Vector.Primitive.Vector (Double)" (testNumericPrimitiveVector (undefined :: Data.Vector.Primitive.Vector Double)),
+
+        testGroup "Data.Vector.Storable.Vector (Int)"    (testNumericStorableVector (undefined :: Data.Vector.Storable.Vector Int)),
+        testGroup "Data.Vector.Storable.Vector (Float)"  (testNumericStorableVector (undefined :: Data.Vector.Storable.Vector Float)),
+        testGroup "Data.Vector.Storable.Vector (Double)" (testNumericStorableVector (undefined :: Data.Vector.Storable.Vector Double))
+    ]
+
diff --git a/tests/Utilities.hs b/tests/Utilities.hs
--- a/tests/Utilities.hs
+++ b/tests/Utilities.hs
@@ -1,61 +1,216 @@
+{-# LANGUAGE FlexibleInstances, GADTs #-}
 module Utilities where
 
 import Test.QuickCheck
 
 import qualified Data.Vector as DV
-import qualified Data.Vector.IVector as DVI
-import qualified Data.Vector.Unboxed as DVU
-import qualified Data.Vector.Unboxed.Unbox as DVUU
+import qualified Data.Vector.Generic as DVG
+import qualified Data.Vector.Primitive as DVP
+import qualified Data.Vector.Storable as DVS
 import qualified Data.Vector.Fusion.Stream as S
 
+import Data.List ( sortBy )
 
+
 instance Show a => Show (S.Stream a) where
     show s = "Data.Vector.Fusion.Stream.fromList " ++ show (S.toList s)
 
 
 instance Arbitrary a => Arbitrary (DV.Vector a) where
     arbitrary = fmap DV.fromList arbitrary
+
+instance CoArbitrary a => CoArbitrary (DV.Vector a) where
     coarbitrary = coarbitrary . DV.toList
 
-instance (Arbitrary a, DVUU.Unbox a) => Arbitrary (DVU.Vector a) where
-    arbitrary = fmap DVU.fromList arbitrary
-    coarbitrary = coarbitrary . DVU.toList
+instance (Arbitrary a, DVP.Prim a) => Arbitrary (DVP.Vector a) where
+    arbitrary = fmap DVP.fromList arbitrary
 
+instance (CoArbitrary a, DVP.Prim a) => CoArbitrary (DVP.Vector a) where
+    coarbitrary = coarbitrary . DVP.toList
+
+instance (Arbitrary a, DVS.Storable a) => Arbitrary (DVS.Vector a) where
+    arbitrary = fmap DVS.fromList arbitrary
+
+instance (CoArbitrary a, DVS.Storable a) => CoArbitrary (DVS.Vector a) where
+    coarbitrary = coarbitrary . DVS.toList
+
 instance Arbitrary a => Arbitrary (S.Stream a) where
     arbitrary = fmap S.fromList arbitrary
+
+instance CoArbitrary a => CoArbitrary (S.Stream a) where
     coarbitrary = coarbitrary . S.toList
 
+class (Testable (EqTest a), Conclusion (EqTest a)) => TestData a where
+  type Model a
+  model :: a -> Model a
+  unmodel :: Model a -> a
 
-class Model a b | a -> b where
-  -- | Convert a concrete value into an abstract model
-  model :: a -> b
+  type EqTest a
+  equal :: a -> a -> EqTest a
 
--- The meat of the models
-instance                 Model (DV.Vector a)  [a] where model = DV.toList
-instance DVUU.Unbox a => Model (DVU.Vector a) [a] where model = DVU.toList
+instance Eq a => TestData (S.Stream a) where
+  type Model (S.Stream a) = [a]
+  model = S.toList
+  unmodel = S.fromList
 
--- Identity models
-instance Model Bool     Bool     where model = id
-instance Model Int      Int      where model = id
-instance Model Float    Float    where model = id
-instance Model Double   Double   where model = id
-instance Model Ordering Ordering where model = id
+  type EqTest (S.Stream a) = Property
+  equal x y = property (x == y)
 
+instance Eq a => TestData (DV.Vector a) where
+  type Model (DV.Vector a) = [a]
+  model = DV.toList
+  unmodel = DV.fromList
+
+  type EqTest (DV.Vector a) = Property
+  equal x y = property (x == y)
+
+instance (Eq a, DVP.Prim a) => TestData (DVP.Vector a) where
+  type Model (DVP.Vector a) = [a]
+  model = DVP.toList
+  unmodel = DVP.fromList
+
+  type EqTest (DVP.Vector a) = Property
+  equal x y = property (x == y)
+
+instance (Eq a, DVS.Storable a) => TestData (DVS.Vector a) where
+  type Model (DVS.Vector a) = [a]
+  model = DVS.toList
+  unmodel = DVS.fromList
+
+  type EqTest (DVS.Vector a) = Property
+  equal x y = property (x == y)
+
+#define id_TestData(ty) \
+instance TestData ty where { \
+  type Model ty = ty;        \
+  model = id;                \
+  unmodel = id;              \
+                             \
+  type EqTest ty = Property; \
+  equal x y = property (x == y) }
+
+id_TestData(Bool)
+id_TestData(Int)
+id_TestData(Float)
+id_TestData(Double)
+id_TestData(Ordering)
+
 -- Functorish models
 -- All of these need UndecidableInstances although they are actually well founded. Oh well.
-instance Model a b                            => Model (Maybe a) (Maybe b)    where model           = fmap model
-instance (Model a a', Model b b')             => Model (a, b) (a', b')        where model (a, b)    = (model a, model b)
-instance (Model a a', Model b b', Model c c') => Model (a, b, c) (a', b', c') where model (a, b, c) = (model a, model b, model c)
-instance (Model c a, Model b d)               => Model (a -> b) (c -> d)      where model f         = model . f . model
+instance (Eq a, TestData a) => TestData (Maybe a) where
+  type Model (Maybe a) = Maybe (Model a)
+  model = fmap model
+  unmodel = fmap unmodel
 
+  type EqTest (Maybe a) = Property
+  equal x y = property (x == y)
 
-eq0 f g =             model f           == g
-eq1 f g = \a       -> model (f a)       == g (model a)
-eq2 f g = \a b     -> model (f a b)     == g (model a) (model b)
-eq3 f g = \a b c   -> model (f a b c)   == g (model a) (model b) (model c)
-eq4 f g = \a b c d -> model (f a b c d) == g (model a) (model b) (model c) (model d)
+instance (Eq a, TestData a) => TestData [a] where
+  type Model [a] = [Model a]
+  model = fmap model
+  unmodel = fmap unmodel
 
-eqNotNull1 f g = \a       -> (not (DVI.null a)) ==> eq1 f g a
-eqNotNull2 f g = \a b     -> (not (DVI.null b)) ==> eq2 f g a b
-eqNotNull3 f g = \a b c   -> (not (DVI.null c)) ==> eq3 f g a b c
-eqNotNull4 f g = \a b c d -> (not (DVI.null d)) ==> eq4 f g a b c d
+  type EqTest [a] = Property
+  equal x y = property (x == y)
+
+instance (Eq a, Eq b, TestData a, TestData b) => TestData (a,b) where
+  type Model (a,b) = (Model a, Model b)
+  model (a,b) = (model a, model b)
+  unmodel (a,b) = (unmodel a, unmodel b)
+
+  type EqTest (a,b) = Property
+  equal x y = property (x == y)
+
+instance (Eq a, Eq b, Eq c, TestData a, TestData b, TestData c) => TestData (a,b,c) where
+  type Model (a,b,c) = (Model a, Model b, Model c)
+  model (a,b,c) = (model a, model b, model c)
+  unmodel (a,b,c) = (unmodel a, unmodel b, unmodel c)
+
+  type EqTest (a,b,c) = Property
+  equal x y = property (x == y)
+
+instance (Arbitrary a, Show a, TestData a, TestData b) => TestData (a -> b) where
+  type Model (a -> b) = Model a -> Model b
+  model f = model . f . unmodel
+  unmodel f = unmodel . f . model
+
+  type EqTest (a -> b) = a -> EqTest b
+  equal f g x = equal (f x) (g x)
+
+newtype P a = P { unP :: EqTest a }
+
+instance TestData a => Testable (P a) where
+  property (P a) = property a
+
+infix 4 `eq`
+eq :: TestData a => a -> Model a -> P a
+eq x y = P (equal x (unmodel y))
+
+class Conclusion p where
+  type Predicate p
+
+  predicate :: Predicate p -> p -> p
+
+instance Conclusion Property where
+  type Predicate Property = Bool
+
+  predicate = (==>)
+
+instance Conclusion p => Conclusion (a -> p) where
+  type Predicate (a -> p) = a -> Predicate p
+
+  predicate f p = \x -> predicate (f x) (p x)
+
+infixr 0 ===>
+(===>) :: TestData a => Predicate (EqTest a) -> P a -> P a
+p ===> P a = P (predicate p a)
+
+notNull2 _ xs = not $ DVG.null xs
+notNullS2 _ s = not $ S.null s
+
+-- Generators
+index_value_pairs :: Arbitrary a => Int -> Gen [(Int,a)]
+index_value_pairs 0 = return [] 
+index_value_pairs m = sized $ \n ->
+  do
+    len <- choose (0,n)
+    is <- sequence [choose (0,m-1) | i <- [1..len]]
+    xs <- vector len
+    return $ zip is xs
+
+indices :: Int -> Gen [Int]
+indices 0 = return []
+indices m = sized $ \n ->
+  do
+    len <- choose (0,n)
+    sequence [choose (0,m-1) | i <- [1..len]]
+
+
+-- Additional list functions
+singleton x = [x]
+snoc xs x = xs ++ [x]
+slice xs i n = take n (drop i xs)
+backpermute xs is = map (xs!!) is
+prescanl f z = init . scanl f z
+postscanl f z = tail . scanl f z
+
+accum :: (a -> b -> a) -> [a] -> [(Int,b)] -> [a]
+accum f xs ps = go xs ps' 0
+  where
+    ps' = sortBy (\p q -> compare (fst p) (fst q)) ps
+
+    go (x:xs) ((i,y) : ps) j
+      | i == j     = go (f x y : xs) ps j
+    go (x:xs) ps j = x : go xs ps (j+1)
+    go [] _ _      = []  
+
+(//) :: [a] -> [(Int, a)] -> [a]
+xs // ps = go xs ps' 0
+  where
+    ps' = sortBy (\p q -> compare (fst p) (fst q)) ps
+
+    go (x:xs) ((i,y) : ps) j
+      | i == j     = go (y:xs) ps j
+    go (x:xs) ps j = x : go xs ps (j+1)
+    go [] _ _      = []
+
diff --git a/tests/vector-tests.cabal b/tests/vector-tests.cabal
--- a/tests/vector-tests.cabal
+++ b/tests/vector-tests.cabal
@@ -23,13 +23,12 @@
               MultiParamTypeClasses,
               FlexibleContexts,
               Rank2Types,
-              FunctionalDependencies,
               TypeSynonymInstances,
-              UndecidableInstances,
+              TypeFamilies,
               TemplateHaskell
 
-  Build-Depends: base, template-haskell, vector,
-                 QuickCheck, test-framework, test-framework-quickcheck
+  Build-Depends: base, template-haskell, vector, random,
+                 QuickCheck >= 2, test-framework, test-framework-quickcheck2
 
   -- Don't let fusion occur or GHC will make our tests less informative in some cases :-)
   Ghc-Options: -O0
diff --git a/vector.cabal b/vector.cabal
--- a/vector.cabal
+++ b/vector.cabal
@@ -1,18 +1,29 @@
 Name:           vector
-Version:        0.3.1
+Version:        0.4
 License:        BSD3
 License-File:   LICENSE
-Author:         Roman Leshchinskiy
+Author:         Roman Leshchinskiy <rl@cse.unsw.edu.au>
 Maintainer:     Roman Leshchinskiy <rl@cse.unsw.edu.au>
-Copyright:      (c) Roman Leshchinskiy 2008
+Copyright:      (c) Roman Leshchinskiy 2008-2009
 Homepage:       http://darcs.haskell.org/vector
-Category:       Data Structures
+Category:       Data, Data Structures
 Synopsis:       Efficient Arrays
 Description:
         .
-        An efficient but highly experimental implementation of Int-indexed
-        arrays with a powerful loop fusion framework.
+        An efficient implementation of Int-indexed arrays with a powerful loop
+        fusion framework.
         .
+        It is structured as follows:
+        .
+        [@Data.Vector@] boxed vectors of arbitrary types
+        .
+        [@Data.Vector.Primitive@] unboxed vectors of primitive types as
+                defined by the @primitive@ package
+        .
+        [@Data.Vector.Storable@] unboxed vectors of 'Storable' types
+        .
+        [@Data.Vector.Generic@] generic interface to the vector types
+        .
 
 Cabal-Version:  >= 1.2
 Build-Type:     Simple
@@ -23,8 +34,9 @@
       tests/Setup.hs
       tests/Main.hs
       tests/Boilerplater.hs
-      tests/Properties.hs
       tests/Utilities.hs
+      tests/Tests/Stream.hs
+      tests/Tests/Vector.hs
 
 Flag EnableAssertions
   Description: Enable assertions that check parameters to functions are reasonable.
@@ -40,17 +52,18 @@
         Data.Vector.Fusion.Stream.Monadic
         Data.Vector.Fusion.Stream
 
-        Data.Vector.MVector
-        Data.Vector.MVector.New
-        Data.Vector.IVector
+        Data.Vector.Generic.Mutable
+        Data.Vector.Generic.New
+        Data.Vector.Generic
 
-        Data.Vector.Unboxed.Unbox
-        Data.Vector.Unboxed.Mutable.ST
-        Data.Vector.Unboxed.Mutable.IO
-        Data.Vector.Unboxed
+        Data.Vector.Primitive.Mutable
+        Data.Vector.Primitive
 
-        Data.Vector.Mutable.ST
-        Data.Vector.Mutable.IO
+        Data.Vector.Storable.Internal
+        Data.Vector.Storable.Mutable
+        Data.Vector.Storable
+
+        Data.Vector.Mutable
         Data.Vector
   Include-Dirs:
         include
@@ -58,14 +71,14 @@
   Install-Includes:
         phases.h
 
-  Build-Depends: base >= 2 && < 4, array, ghc-prim,
-                 ghc >= 6.9
+  Build-Depends: base >= 2 && < 5, ghc >= 6.9, primitive
 
 -- -finline-if-enough-args is ESSENTIAL. If we don't have this the partial application
 -- of e.g. Stream.Monadic.++ to the monad dictionary at the use site in Stream.++ causes
 -- it to be fruitlessly inlined. This in turn leads to a huge RHS for Stream.++, so it
 -- doesn't get inlined at the final call site and fusion fails to occur.
-  Ghc-Options: -finline-if-enough-args
+  if impl(ghc<6.13)
+    Ghc-Options: -finline-if-enough-args
   
 -- It's probably a good idea to compile the library with -O2 as well. However, it's probably
 -- not as essential as you think because most of the optimisation occurs when the library
