diff --git a/Data/Vector.hs b/Data/Vector.hs
--- a/Data/Vector.hs
+++ b/Data/Vector.hs
@@ -1,33 +1,68 @@
-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeFamilies #-}
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeFamilies, Rank2Types #-}
 
 -- |
 -- Module      : Data.Vector
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
 -- Stability   : experimental
 -- Portability : non-portable
 -- 
--- Boxed vectors
+-- A library for boxed vectors (that is, polymorphic arrays capable of
+-- holding any Haskell value). The vectors come in two flavors:
 --
+--  * mutable
+--
+--  * immutable
+--
+-- and support a rich interface of both list-like operations, and bulk
+-- array operations.
+--
+-- For unboxed arrays, use the 'Data.Vector.Unboxed' interface.
+--
 
 module Data.Vector (
+
+  -- * The pure and mutable array types
   Vector, MVector,
 
-  -- * Length information
-  length, null,
+  -- * Constructing vectors
+  empty,
+  singleton,
+  cons,
+  snoc,
+  (++),
+  replicate,
+  generate,
+  force,
 
-  -- * Construction
-  empty, singleton, cons, snoc, replicate, generate, (++), copy,
+  -- * Operations based on length information
+  length,
+  null,
 
   -- * Accessing individual elements
-  (!), head, last, indexM, headM, lastM,
+  (!),
+  head,
+  last,
+
+  -- ** Accessors in a monad
+  indexM,
+  headM,
+  lastM,
+
+  -- ** Accessor functions with no bounds checking
   unsafeIndex, unsafeHead, unsafeLast,
   unsafeIndexM, unsafeHeadM, unsafeLastM,
 
   -- * Subvectors
-  slice, init, tail, take, drop,
+  init,
+  tail,
+  take,
+  drop,
+  slice,
+
+  -- * Subvector construction without bounds checks
   unsafeSlice, unsafeInit, unsafeTail, unsafeTake, unsafeDrop,
 
   -- * Permutations
@@ -65,7 +100,7 @@
   minIndex, minIndexBy, maxIndex, maxIndexBy,
 
   -- * Unfolding
-  unfoldr,
+  unfoldr, unfoldrN,
 
   -- * Scans
   prescanl, prescanl',
@@ -79,14 +114,24 @@
   enumFromN, enumFromStepN, enumFromTo, enumFromThenTo,
 
   -- * Conversion to/from lists
-  toList, fromList
+  toList, fromList, fromListN,
+
+  -- * Monadic operations
+  replicateM, mapM, mapM_, forM, forM_, zipWithM, zipWithM_, filterM,
+  foldM, foldM', fold1M, fold1M',
+
+  -- * Destructive operations
+  create, modify, copy, unsafeCopy
 ) where
 
 import qualified Data.Vector.Generic as G
 import           Data.Vector.Mutable  ( MVector(..) )
 import           Data.Primitive.Array
+import qualified Data.Vector.Fusion.Stream as Stream
 
 import Control.Monad ( liftM )
+import Control.Monad.ST ( ST )
+import Control.Monad.Primitive
 
 import Prelude hiding ( length, null,
                         replicate, (++),
@@ -99,17 +144,30 @@
                         foldl, foldl1, foldr, foldr1,
                         all, any, and, or, sum, product, minimum, maximum,
                         scanl, scanl1, scanr, scanr1,
-                        enumFromTo, enumFromThenTo )
+                        enumFromTo, enumFromThenTo,
+                        mapM, mapM_ )
 
 import qualified Prelude
 
+import Data.Typeable ( Typeable )
+import Data.Data     ( Data(..) )
+
+-- | Boxed vectors, supporting efficient slicing.
 data Vector a = Vector {-# UNPACK #-} !Int
                        {-# UNPACK #-} !Int
                        {-# UNPACK #-} !(Array a)
+        deriving ( Typeable )
 
 instance Show a => Show (Vector a) where
     show = (Prelude.++ " :: Data.Vector.Vector") . ("fromList " Prelude.++) . show . toList
 
+instance Data a => Data (Vector a) where
+  gfoldl       = G.gfoldl
+  toConstr _   = error "toConstr"
+  gunfold _ _  = error "gunfold"
+  dataTypeOf _ = G.mkType "Data.Vector.Vector"
+  dataCast1    = G.dataCast
+
 type instance G.Mutable Vector = MVector
 
 instance G.Vector Vector a where
@@ -126,21 +184,40 @@
   {-# INLINE basicUnsafeIndexM #-}
   basicUnsafeIndexM (Vector i _ arr) j = indexArrayM arr (i+j)
 
+-- See http://trac.haskell.org/vector/ticket/12
 instance Eq a => Eq (Vector a) where
   {-# INLINE (==) #-}
-  (==) = G.eq
+  xs == ys = Stream.eq (G.stream xs) (G.stream ys)
 
+  {-# INLINE (/=) #-}
+  xs /= ys = not (Stream.eq (G.stream xs) (G.stream ys))
+
+-- See http://trac.haskell.org/vector/ticket/12
 instance Ord a => Ord (Vector a) where
   {-# INLINE compare #-}
-  compare = G.cmp
+  compare xs ys = Stream.cmp (G.stream xs) (G.stream ys)
 
+  {-# INLINE (<) #-}
+  xs < ys = Stream.cmp (G.stream xs) (G.stream ys) == LT
+
+  {-# INLINE (<=) #-}
+  xs <= ys = Stream.cmp (G.stream xs) (G.stream ys) /= GT
+
+  {-# INLINE (>) #-}
+  xs > ys = Stream.cmp (G.stream xs) (G.stream ys) == GT
+
+  {-# INLINE (>=) #-}
+  xs >= ys = Stream.cmp (G.stream xs) (G.stream ys) /= LT
+
 -- Length
 -- ------
 
+-- |/O(1)/. Yield the length of a vector as an 'Int'
 length :: Vector a -> Int
 {-# INLINE length #-}
 length = G.length
 
+-- |/O(1)/. 'null' tests whether the given array is empty.
 null :: Vector a -> Bool
 {-# INLINE null #-}
 null = G.null
@@ -148,93 +225,106 @@
 -- Construction
 -- ------------
 
--- | Empty vector
+-- |/O(1)/. 'empty' builds a vector of size zero.
 empty :: Vector a
 {-# INLINE empty #-}
 empty = G.empty
 
--- | Vector with exaclty one element
+-- |/O(1)/, Vector with exactly one element
 singleton :: a -> Vector a
 {-# INLINE singleton #-}
 singleton = G.singleton
 
--- | Vector of the given length with the given value in each position
+-- |/O(n)/. @'replicate' n e@ yields a vector of length @n@ storing @e@ at each position
 replicate :: Int -> a -> Vector a
 {-# INLINE replicate #-}
 replicate = G.replicate
 
--- | Generate a vector of the given length by applying the function to each
--- index
+-- |/O(n)/, Generate a vector of the given length by applying a (pure)
+-- generator function to each index
 generate :: Int -> (Int -> a) -> Vector a
 {-# INLINE generate #-}
 generate = G.generate
 
--- | Prepend an element
+-- |/O(n)/, Prepend an element to an array.
 cons :: a -> Vector a -> Vector a
 {-# INLINE cons #-}
 cons = G.cons
 
--- | Append an element
+-- |/O(n)/, Append an element to an array.
 snoc :: Vector a -> a -> Vector a
 {-# INLINE snoc #-}
 snoc = G.snoc
 
 infixr 5 ++
--- | Concatenate two vectors
+
+-- |/O(n)/, Concatenate two vectors
 (++) :: Vector a -> Vector a -> Vector a
 {-# INLINE (++) #-}
 (++) = (G.++)
 
--- | Create a copy of a vector. Useful when dealing with slices.
-copy :: Vector a -> Vector a
-{-# INLINE copy #-}
-copy = G.copy
+-- |/O(n)/, Create a copy of a vector.
+-- @force@ is useful when dealing with slices, as the garbage collector
+-- may be able to free the original vector if no further references are held.
+--
+force :: Vector a -> Vector a
+{-# INLINE force #-}
+force = G.force
 
 -- Accessing individual elements
 -- -----------------------------
 
--- | Indexing
+-- |/O(1)/. Read the element in the vector at the given index.
 (!) :: Vector a -> Int -> a
 {-# INLINE (!) #-}
 (!) = (G.!)
 
--- | First element
+-- |/O(1)/. 'head' returns the first element of the vector
 head :: Vector a -> a
 {-# INLINE head #-}
 head = G.head
 
--- | Last element
+-- |/O(n)/. 'last' yields the last element of an array.
 last :: Vector a -> a
 {-# INLINE last #-}
 last = G.last
 
--- | Unsafe indexing without bounds checking
+-- |/O(1)/, Unsafe indexing without bounds checking
+--
+-- By not performing bounds checks, this function may be faster when
+-- this function is used in an inner loop)
+--
 unsafeIndex :: Vector a -> Int -> a
 {-# INLINE unsafeIndex #-}
 unsafeIndex = G.unsafeIndex
 
--- | Yield the first element of a vector without checking if the vector is
--- empty
+-- |/O(1)/, Yield the first element of a vector without checking if the vector is empty
+--
+-- By not performing bounds checks, this function may be faster when
+-- this function is used in an inner loop)
 unsafeHead :: Vector a -> a
 {-# INLINE unsafeHead #-}
 unsafeHead = G.unsafeHead
 
--- | Yield the last element of a vector without checking if the vector is
--- empty
+-- | Yield the last element of a vector without checking if the vector is empty
+--
+-- By not performing bounds checks, this function may be faster when
+-- this function is used in an inner loop)
 unsafeLast :: Vector a -> a
 {-# INLINE unsafeLast #-}
 unsafeLast = G.unsafeLast
 
--- | Monadic indexing which can be strict in the vector while remaining lazy in
--- the element
+-- | 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 = G.indexM
 
+-- | Monadic head which can be strict in the vector while remaining lazy in the element
 headM :: Monad m => Vector a -> m a
 {-# INLINE headM #-}
 headM = G.headM
 
+-- | Monadic last which can be strict in the vector while remaining lazy in the element
 lastM :: Monad m => Vector a -> m a
 {-# INLINE lastM #-}
 lastM = G.lastM
@@ -244,10 +334,12 @@
 {-# INLINE unsafeIndexM #-}
 unsafeIndexM = G.unsafeIndexM
 
+-- | Unsafe monadic head (access the first element) without bounds checks
 unsafeHeadM :: Monad m => Vector a -> m a
 {-# INLINE unsafeHeadM #-}
 unsafeHeadM = G.unsafeHeadM
 
+-- | Unsafe monadic last (access the last element) without bounds checks
 unsafeLastM :: Monad m => Vector a -> m a
 {-# INLINE unsafeLastM #-}
 unsafeLastM = G.unsafeLastM
@@ -255,8 +347,8 @@
 -- Subarrays
 -- ---------
 
--- | Yield a part of the vector without copying it. Safer version of
--- 'basicUnsafeSlice'.
+-- | /O(1)/, Yield a part of the vector without copying it.
+--
 slice :: Int   -- ^ starting index
       -> Int   -- ^ length
       -> Vector a
@@ -264,27 +356,27 @@
 {-# INLINE slice #-}
 slice = G.slice
 
--- | Yield all but the last element without copying.
+-- |/O(1)/, Yield all but the last element without copying.
 init :: Vector a -> Vector a
 {-# INLINE init #-}
 init = G.init
 
--- | All but the first element (without copying).
+-- |/O(1), Yield all but the first element (without copying).
 tail :: Vector a -> Vector a
 {-# INLINE tail #-}
 tail = G.tail
 
--- | Yield the first @n@ elements without copying.
+-- |/O(1)/, Yield the first @n@ elements without copying.
 take :: Int -> Vector a -> Vector a
 {-# INLINE take #-}
 take = G.take
 
--- | Yield all but the first @n@ elements without copying.
+-- |/O(1)/, Yield all but the first @n@ elements without copying.
 drop :: Int -> Vector a -> Vector a
 {-# INLINE drop #-}
 drop = G.drop
 
--- | Unsafely yield a part of the vector without copying it and without
+-- |/O(1)/, Unsafely yield a part of the vector without copying it and without
 -- performing bounds checks.
 unsafeSlice :: Int   -- ^ starting index
             -> Int   -- ^ length
@@ -293,18 +385,22 @@
 {-# INLINE unsafeSlice #-}
 unsafeSlice = G.unsafeSlice
 
+-- |/O(1)/, Zero-copying 'init' without bounds checks.
 unsafeInit :: Vector a -> Vector a
 {-# INLINE unsafeInit #-}
 unsafeInit = G.unsafeInit
 
+-- |/O(1)/, Zero-copying 'tail' without bounds checks.
 unsafeTail :: Vector a -> Vector a
 {-# INLINE unsafeTail #-}
 unsafeTail = G.unsafeTail
 
+-- |/O(1)/, Zero-copying 'take' without bounds checks.
 unsafeTake :: Int -> Vector a -> Vector a
 {-# INLINE unsafeTake #-}
 unsafeTake = G.unsafeTake
 
+-- |/O(1)/, Zero-copying 'drop' without bounds checks.
 unsafeDrop :: Int -> Vector a -> Vector a
 {-# INLINE unsafeDrop #-}
 unsafeDrop = G.unsafeDrop
@@ -312,63 +408,80 @@
 -- Permutations
 -- ------------
 
+-- TODO there is no documentation for the accum* family of functions
+
+-- | TODO unsafeAccum.
 unsafeAccum :: (a -> b -> a) -> Vector a -> [(Int,b)] -> Vector a
 {-# INLINE unsafeAccum #-}
 unsafeAccum = G.unsafeAccum
 
+-- | TODO unsafeAccumulate
 unsafeAccumulate :: (a -> b -> a) -> Vector a -> Vector (Int,b) -> Vector a
 {-# INLINE unsafeAccumulate #-}
 unsafeAccumulate = G.unsafeAccumulate
 
+-- | TODO unsafeAccumulate_
 unsafeAccumulate_
   :: (a -> b -> a) -> Vector a -> Vector Int -> Vector b -> Vector a
 {-# INLINE unsafeAccumulate_ #-}
 unsafeAccumulate_ = G.unsafeAccumulate_
 
+-- | TODO accum
 accum :: (a -> b -> a) -> Vector a -> [(Int,b)] -> Vector a
 {-# INLINE accum #-}
 accum = G.accum
 
+-- | TODO accumulate
 accumulate :: (a -> b -> a) -> Vector a -> Vector (Int,b) -> Vector a
 {-# INLINE accumulate #-}
 accumulate = G.accumulate
 
+-- | TODO accumulate_
 accumulate_ :: (a -> b -> a) -> Vector a -> Vector Int -> Vector b -> Vector a
 {-# INLINE accumulate_ #-}
 accumulate_ = G.accumulate_
 
+-- | TODO unsafeUpd
 unsafeUpd :: Vector a -> [(Int, a)] -> Vector a
 {-# INLINE unsafeUpd #-}
 unsafeUpd = G.unsafeUpd
 
+-- | TODO unsafeUpdate
 unsafeUpdate :: Vector a -> Vector (Int, a) -> Vector a
 {-# INLINE unsafeUpdate #-}
 unsafeUpdate = G.unsafeUpdate
 
+-- | TODO unsafeUpdate_
 unsafeUpdate_ :: Vector a -> Vector Int -> Vector a -> Vector a
 {-# INLINE unsafeUpdate_ #-}
 unsafeUpdate_ = G.unsafeUpdate_
 
+-- | TODO (//)
 (//) :: Vector a -> [(Int, a)] -> Vector a
 {-# INLINE (//) #-}
 (//) = (G.//)
 
+-- | TODO update
 update :: Vector a -> Vector (Int, a) -> Vector a
 {-# INLINE update #-}
 update = G.update
 
+-- | TODO update_
 update_ :: Vector a -> Vector Int -> Vector a -> Vector a
 {-# INLINE update_ #-}
 update_ = G.update_
 
+-- | backpermute, courtesy Blelloch. The back-permute is a gather\/get operation.
 backpermute :: Vector a -> Vector Int -> Vector a
 {-# INLINE backpermute #-}
 backpermute = G.backpermute
 
+-- | TODO unsafeBackpermute
 unsafeBackpermute :: Vector a -> Vector Int -> Vector a
 {-# INLINE unsafeBackpermute #-}
 unsafeBackpermute = G.unsafeBackpermute
 
+-- | /O(n)/, reverse the elements of the given vector.
 reverse :: Vector a -> Vector a
 {-# INLINE reverse #-}
 reverse = G.reverse
@@ -376,16 +489,17 @@
 -- Mapping
 -- -------
 
--- | Map a function over a vector
+-- | /O(n)/, Map a function over a vector
 map :: (a -> b) -> Vector a -> Vector b
 {-# INLINE map #-}
 map = G.map
 
--- | Apply a function to every index/value pair
+-- | /O(n)/, Apply a function to every index/value pair yielding a new vector
 imap :: (Int -> a -> b) -> Vector a -> Vector b
 {-# INLINE imap #-}
 imap = G.imap
 
+-- | /O(n)/, generate a vector from each element of the input vector, then join the results.
 concatMap :: (a -> Vector b) -> Vector a -> Vector b
 {-# INLINE concatMap #-}
 concatMap = G.concatMap
@@ -393,65 +507,73 @@
 -- Zipping/unzipping
 -- -----------------
 
--- | Zip two vectors with the given function.
+-- |/O(n)/, Zip two vectors with the given function.
 zipWith :: (a -> b -> c) -> Vector a -> Vector b -> Vector c
 {-# INLINE zipWith #-}
 zipWith = G.zipWith
 
--- | Zip three vectors with the given function.
+-- |/O(n)/, Zip three vectors with the given function.
 zipWith3 :: (a -> b -> c -> d) -> Vector a -> Vector b -> Vector c -> Vector d
 {-# INLINE zipWith3 #-}
 zipWith3 = G.zipWith3
 
+-- |/O(n)/, Zip four vectors with the given function.
 zipWith4 :: (a -> b -> c -> d -> e)
           -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e
 {-# INLINE zipWith4 #-}
 zipWith4 = G.zipWith4
 
+-- |/O(n)/, Zip five vectors with the given function.
 zipWith5 :: (a -> b -> c -> d -> e -> f)
           -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e
           -> Vector f
 {-# INLINE zipWith5 #-}
 zipWith5 = G.zipWith5
 
+-- |/O(n)/, Zip six vectors with the given function.
 zipWith6 :: (a -> b -> c -> d -> e -> f -> g)
           -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e
           -> Vector f -> Vector g
 {-# INLINE zipWith6 #-}
 zipWith6 = G.zipWith6
 
--- | Zip two vectors and their indices with the given function.
+-- |/O(n)/, Zip two vectors and their indices with the given function.
 izipWith :: (Int -> a -> b -> c) -> Vector a -> Vector b -> Vector c
 {-# INLINE izipWith #-}
 izipWith = G.izipWith
 
--- | Zip three vectors and their indices with the given function.
+-- |/O(n)/, Zip three vectors and their indices with the given function.
 izipWith3 :: (Int -> a -> b -> c -> d)
           -> Vector a -> Vector b -> Vector c -> Vector d
 {-# INLINE izipWith3 #-}
 izipWith3 = G.izipWith3
 
+-- |/O(n)/, Zip four vectors and their indices with the given function.
 izipWith4 :: (Int -> a -> b -> c -> d -> e)
           -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e
 {-# INLINE izipWith4 #-}
 izipWith4 = G.izipWith4
 
+-- |/O(n)/, Zip five vectors and their indices with the given function.
 izipWith5 :: (Int -> a -> b -> c -> d -> e -> f)
           -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e
           -> Vector f
 {-# INLINE izipWith5 #-}
 izipWith5 = G.izipWith5
 
+-- |/O(n)/, Zip six vectors and their indices with the given function.
 izipWith6 :: (Int -> a -> b -> c -> d -> e -> f -> g)
           -> Vector a -> Vector b -> Vector c -> Vector d -> Vector e
           -> Vector f -> Vector g
 {-# INLINE izipWith6 #-}
 izipWith6 = G.izipWith6
 
+-- | Elementwise pairing of array elements. 
 zip :: Vector a -> Vector b -> Vector (a, b)
 {-# INLINE zip #-}
 zip = G.zip
 
+-- | zip together three vectors into a vector of triples
 zip3 :: Vector a -> Vector b -> Vector c -> Vector (a, b, c)
 {-# INLINE zip3 #-}
 zip3 = G.zip3
@@ -471,6 +593,7 @@
 {-# INLINE zip6 #-}
 zip6 = G.zip6
 
+-- | Elementwise unpairing of array elements.
 unzip :: Vector (a, b) -> (Vector a, Vector b)
 {-# INLINE unzip #-}
 unzip = G.unzip
@@ -496,23 +619,23 @@
 -- Filtering
 -- ---------
 
--- | Drop elements which do not satisfy the predicate
+-- |/O(n)/, Remove elements from the vector which do not satisfy the predicate
 filter :: (a -> Bool) -> Vector a -> Vector a
 {-# INLINE filter #-}
 filter = G.filter
 
--- | Drop elements that do not satisfy the predicate (applied to values and
+-- |/O(n)/, Drop elements that do not satisfy the predicate (applied to values and
 -- their indices)
 ifilter :: (Int -> a -> Bool) -> Vector a -> Vector a
 {-# INLINE ifilter #-}
 ifilter = G.ifilter
 
--- | Yield the longest prefix of elements satisfying the predicate.
+-- |/O(n)/, Yield the longest prefix of elements satisfying the predicate.
 takeWhile :: (a -> Bool) -> Vector a -> Vector a
 {-# INLINE takeWhile #-}
 takeWhile = G.takeWhile
 
--- | Drop the longest prefix of elements that satisfy the predicate.
+-- |/O(n)/, Drop the longest prefix of elements that satisfy the predicate.
 dropWhile :: (a -> Bool) -> Vector a -> Vector a
 {-# INLINE dropWhile #-}
 dropWhile = G.dropWhile
@@ -525,14 +648,14 @@
 {-# INLINE partition #-}
 partition = G.partition
 
--- | Split the vector in two parts, the first one containing those elements
+-- |/O(n)/, Split the vector in two parts, the first one containing those elements
 -- that satisfy the predicate and the second one those that don't. The order
 -- of the elements is not preserved.
 unstablePartition :: (a -> Bool) -> Vector a -> (Vector a, Vector a)
 {-# INLINE unstablePartition #-}
 unstablePartition = G.unstablePartition
 
--- | Split the vector into the longest prefix of elements that satisfy the
+-- |/O(n)/, Split the vector into the longest prefix of elements that satisfy the
 -- predicate and the rest.
 span :: (a -> Bool) -> Vector a -> (Vector a, Vector a)
 {-# INLINE span #-}
@@ -595,7 +718,7 @@
 {-# INLINE foldl #-}
 foldl = G.foldl
 
--- | Lefgt fold on non-empty vectors
+-- | Left fold on non-empty vectors
 foldl1 :: (a -> a -> a) -> Vector a -> a
 {-# INLINE foldl1 #-}
 foldl1 = G.foldl1
@@ -655,58 +778,74 @@
 -- Specialised folds
 -- -----------------
 
+-- |/O(n)/. @'all' p u@ determines whether all elements in array @u@ satisfy 
+-- predicate @p@.
 all :: (a -> Bool) -> Vector a -> Bool
 {-# INLINE all #-}
 all = G.all
 
+-- |/O(n)/. @'any' p u@ determines whether any element in array @u@ satisfies
+-- predicate @p@.
 any :: (a -> Bool) -> Vector a -> Bool
 {-# INLINE any #-}
 any = G.any
 
+-- |/O(n)/. 'and' yields the conjunction of a boolean array.
 and :: Vector Bool -> Bool
 {-# INLINE and #-}
 and = G.and
 
+-- |/O(n)/. 'or' yields the disjunction of a boolean array.
 or :: Vector Bool -> Bool
 {-# INLINE or #-}
 or = G.or
 
+-- |/O(n)/. 'sum' computes the sum (with @(+)@) of an array of elements.
 sum :: Num a => Vector a -> a
 {-# INLINE sum #-}
 sum = G.sum
 
+-- |/O(n)/. 'sum' computes the product (with @(*)@) of an array of elements.
 product :: Num a => Vector a -> a
 {-# INLINE product #-}
 product = G.product
 
+-- |/O(n)/. 'maximum' finds the maximum element in an array of orderable elements.
 maximum :: Ord a => Vector a -> a
 {-# INLINE maximum #-}
 maximum = G.maximum
 
+-- |/O(n)/. 'maximumBy' finds the maximum element in an array under the given ordering.
 maximumBy :: (a -> a -> Ordering) -> Vector a -> a
 {-# INLINE maximumBy #-}
 maximumBy = G.maximumBy
 
+-- |/O(n)/. 'minimum' finds the minimum element in an array of orderable elements.
 minimum :: Ord a => Vector a -> a
 {-# INLINE minimum #-}
 minimum = G.minimum
 
+-- |/O(n)/. 'minimumBy' finds the minimum element in an array under the given ordering.
 minimumBy :: (a -> a -> Ordering) -> Vector a -> a
 {-# INLINE minimumBy #-}
 minimumBy = G.minimumBy
 
+-- | TODO maxIndex
 maxIndex :: Ord a => Vector a -> Int
 {-# INLINE maxIndex #-}
 maxIndex = G.maxIndex
 
+-- | TODO maxIndexBy
 maxIndexBy :: (a -> a -> Ordering) -> Vector a -> Int
 {-# INLINE maxIndexBy #-}
 maxIndexBy = G.maxIndexBy
 
+-- | TODO minIndex
 minIndex :: Ord a => Vector a -> Int
 {-# INLINE minIndex #-}
 minIndex = G.minIndex
 
+-- | TODO minIndexBy
 minIndexBy :: (a -> a -> Ordering) -> Vector a -> Int
 {-# INLINE minIndexBy #-}
 minIndexBy = G.minIndexBy
@@ -714,10 +853,27 @@
 -- Unfolding
 -- ---------
 
+-- | The 'unfoldr' function is a \`dual\' to 'foldr': while 'foldr'
+-- reduces a vector to a summary value, 'unfoldr' builds a list from
+-- a seed value.  The function takes the element and returns 'Nothing'
+-- if it is done generating the vector or returns 'Just' @(a,b)@, in which
+-- case, @a@ is a prepended to the vector and @b@ is used as the next
+-- element in a recursive call.
+--
+-- A simple use of unfoldr:
+--
+-- > unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
+-- >  [10,9,8,7,6,5,4,3,2,1]
+--
 unfoldr :: (b -> Maybe (a, b)) -> b -> Vector a
 {-# INLINE unfoldr #-}
 unfoldr = G.unfoldr
 
+-- | Unfold at most @n@ elements
+unfoldrN :: Int -> (b -> Maybe (a, b)) -> b -> Vector a
+{-# INLINE unfoldrN #-}
+unfoldrN = G.unfoldrN
+
 -- Scans
 -- -----
 
@@ -741,7 +897,7 @@
 {-# INLINE postscanl' #-}
 postscanl' = G.postscanl'
 
--- | Haskell-style scan
+-- | Haskell-style scan function.
 scanl :: (a -> b -> a) -> a -> Vector b -> Vector a
 {-# INLINE scanl #-}
 scanl = G.scanl
@@ -761,7 +917,6 @@
 {-# INLINE scanl1' #-}
 scanl1' = G.scanl1'
 
-
 -- | Prefix right-to-left scan
 prescanr :: (a -> b -> b) -> b -> Vector a -> Vector b
 {-# INLINE prescanr #-}
@@ -846,4 +1001,107 @@
 fromList :: [a] -> Vector a
 {-# INLINE fromList #-}
 fromList = G.fromList
+
+-- | Convert the first @n@ elements of a list to a vector
+--
+-- > fromListN n xs = fromList (take n xs)
+fromListN :: Int -> [a] -> Vector a
+{-# INLINE fromListN #-}
+fromListN = G.fromListN
+
+-- Monadic operations
+-- ------------------
+
+-- | Perform the monadic action the given number of times and store the
+-- results in a vector.
+replicateM :: Monad m => Int -> m a -> m (Vector a)
+{-# INLINE replicateM #-}
+replicateM = G.replicateM
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+mapM :: Monad m => (a -> m b) -> Vector a -> m (Vector b)
+{-# INLINE mapM #-}
+mapM = G.mapM
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+mapM_ :: Monad m => (a -> m b) -> Vector a -> m ()
+{-# INLINE mapM_ #-}
+mapM_ = G.mapM_
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+forM :: Monad m => Vector a -> (a -> m b) -> m (Vector b)
+{-# INLINE forM #-}
+forM = G.forM
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+forM_ :: Monad m => Vector a -> (a -> m b) -> m ()
+{-# INLINE forM_ #-}
+forM_ = G.forM_
+
+-- | Zip the two vectors with the monadic action and yield a vector of results
+zipWithM :: Monad m
+         => (a -> b -> m c) -> Vector a -> Vector b -> m (Vector c)
+{-# INLINE zipWithM #-}
+zipWithM = G.zipWithM
+
+-- | Zip the two vectors with the monadic action and ignore the results
+zipWithM_ :: Monad m
+          => (a -> b -> m c) -> Vector a -> Vector b -> m ()
+{-# INLINE zipWithM_ #-}
+zipWithM_ = G.zipWithM_
+
+-- | Drop elements that do not satisfy the monadic predicate
+filterM :: Monad m => (a -> m Bool) -> Vector a -> m (Vector a)
+{-# INLINE filterM #-}
+filterM = G.filterM
+
+-- | Monadic fold
+foldM :: Monad m => (a -> b -> m a) -> a -> Vector b -> m a
+{-# INLINE foldM #-}
+foldM = G.foldM
+
+-- | Monadic fold over non-empty vectors
+fold1M :: Monad m => (a -> a -> m a) -> Vector a -> m a
+{-# INLINE fold1M #-}
+fold1M = G.fold1M
+
+-- | Monadic fold with strict accumulator
+foldM' :: Monad m => (a -> b -> m a) -> a -> Vector b -> m a
+{-# INLINE foldM' #-}
+foldM' = G.foldM'
+
+-- | Monad fold over non-empty vectors with strict accumulator
+fold1M' :: Monad m => (a -> a -> m a) -> Vector a -> m a
+{-# INLINE fold1M' #-}
+fold1M' = G.fold1M'
+
+-- Destructive operations
+-- ----------------------
+
+-- | Destructively initialise a vector.
+create :: (forall s. ST s (MVector s a)) -> Vector a
+{-# INLINE create #-}
+create = G.create
+
+-- | Apply a destructive operation to a vector. The operation is applied to a
+-- copy of the vector unless it can be safely performed in place.
+modify :: (forall s. MVector s a -> ST s ()) -> Vector a -> Vector a
+{-# INLINE modify #-}
+modify = G.modify
+
+-- | Copy an immutable vector into a mutable one. The two vectors must have
+-- the same length. This is not checked.
+unsafeCopy :: PrimMonad m => MVector (PrimState m) a -> Vector a -> m ()
+{-# INLINE unsafeCopy #-}
+unsafeCopy = G.unsafeCopy
+           
+-- | Copy an immutable vector into a mutable one. The two vectors must have the
+-- same length.
+copy :: PrimMonad m => MVector (PrimState m) a -> Vector a -> m ()
+{-# INLINE copy #-}
+copy = G.copy
 
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, Rank2Types #-}
+{-# LANGUAGE FlexibleInstances, Rank2Types #-}
 
 -- |
 -- Module      : Data.Vector.Fusion.Stream
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -55,7 +55,7 @@
   and, or,
 
   -- * Unfolding
-  unfoldr,
+  unfoldr, unfoldrN,
 
   -- * Scans
   prescanl, prescanl',
@@ -67,10 +67,12 @@
   enumFromStepN, enumFromTo, enumFromThenTo,
 
   -- * Conversions
-  toList, fromList, liftStream,
+  toList, fromList, fromListN, unsafeFromList, liftStream,
 
   -- * Monadic combinators
-  mapM_, foldM, fold1M, foldM', fold1M'
+  mapM, mapM_, zipWithM, zipWithM_, filterM, foldM, fold1M, foldM', fold1M',
+
+  eq, cmp
 ) where
 
 import Data.Vector.Fusion.Stream.Size
@@ -90,8 +92,10 @@
                         and, or,
                         scanl, scanl1,
                         enumFromTo, enumFromThenTo,
-                        mapM_ )
+                        mapM, mapM_ )
 
+import GHC.Base ( build )
+
 #include "vector.h"
 
 -- | The type of pure streams 
@@ -409,6 +413,11 @@
 {-# INLINE unfoldr #-}
 unfoldr = M.unfoldr
 
+-- | Unfold at most @n@ elements
+unfoldrN :: Int -> (s -> Maybe (a, s)) -> s -> Stream a
+{-# INLINE unfoldrN #-}
+unfoldrN = M.unfoldrN
+
 -- Scans
 -- -----
 
@@ -500,11 +509,30 @@
 -- Monadic combinators
 -- -------------------
 
+-- | Apply a monadic action to each element of the stream, producing a monadic
+-- stream of results
+mapM :: Monad m => (a -> m b) -> Stream a -> M.Stream m b
+{-# INLINE mapM #-}
+mapM f = M.mapM f . liftStream
+
 -- | Apply a monadic action to each element of the stream
-mapM_ :: Monad m => (a -> m ()) -> Stream a -> m ()
+mapM_ :: Monad m => (a -> m b) -> Stream a -> m ()
 {-# INLINE mapM_ #-}
 mapM_ f = M.mapM_ f . liftStream
 
+zipWithM :: Monad m => (a -> b -> m c) -> Stream a -> Stream b -> M.Stream m c
+{-# INLINE zipWithM #-}
+zipWithM f as bs = M.zipWithM f (liftStream as) (liftStream bs)
+
+zipWithM_ :: Monad m => (a -> b -> m c) -> Stream a -> Stream b -> m ()
+{-# INLINE zipWithM_ #-}
+zipWithM_ f as bs = M.zipWithM_ f (liftStream as) (liftStream bs)
+
+-- | Yield a monadic stream of elements that satisfy the monadic predicate
+filterM :: Monad m => (a -> m Bool) -> Stream a -> M.Stream m a
+{-# INLINE filterM #-}
+filterM f = M.filterM f . liftStream
+
 -- | Monadic fold
 foldM :: Monad m => (a -> b -> m a) -> a -> Stream b -> m a
 {-# INLINE foldM #-}
@@ -556,10 +584,33 @@
 -- | Convert a 'Stream' to a list
 toList :: Stream a -> [a]
 {-# INLINE toList #-}
-toList s = unId (M.toList s)
+-- toList s = unId (M.toList s)
+toList s = build (\c n -> toListFB c n s)
 
+-- This supports foldr/build list fusion that GHC implements
+toListFB :: (a -> b -> b) -> b -> Stream a -> b
+{-# INLINE [0] toListFB #-}
+toListFB c n (M.Stream step s _) = go s
+  where
+    go s = case unId (step s) of
+             Yield x s' -> x `c` go s'
+             Skip    s' -> go s'
+             Done       -> n
+
 -- | Create a 'Stream' from a list
 fromList :: [a] -> Stream a
 {-# INLINE fromList #-}
 fromList = M.fromList
+
+-- | Create a 'Stream' from the first @n@ elements of a list
+--
+-- > fromListN n xs = fromList (take n xs)
+fromListN :: Int -> [a] -> Stream a
+{-# INLINE fromListN #-}
+fromListN = M.fromListN
+
+unsafeFromList :: Size -> [a] -> Stream a
+{-# INLINE unsafeFromList #-}
+unsafeFromList = M.unsafeFromList
+
 
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,14 +2,14 @@
 
 -- |
 -- Module      : Data.Vector.Fusion.Stream.Monadic
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
 -- Stability   : experimental
 -- Portability : non-portable
 --
--- Monadic streams
+-- Monadic stream combinators.
 --
 
 module Data.Vector.Fusion.Stream.Monadic (
@@ -22,7 +22,7 @@
   length, null,
 
   -- * Construction
-  empty, singleton, cons, snoc, replicate, generate, generateM, (++),
+  empty, singleton, cons, snoc, replicate, replicateM, generate, generateM, (++),
 
   -- * Accessing elements
   head, last, (!!),
@@ -34,7 +34,7 @@
   map, mapM, mapM_, trans, unbox, concatMap,
   
   -- * Zipping
-  indexed, indexedR,
+  indexed, indexedR, zipWithM_,
   zipWithM, zipWith3M, zipWith4M, zipWith5M, zipWith6M,
   zipWith, zipWith3, zipWith4, zipWith5, zipWith6,
   zip, zip3, zip4, zip5, zip6,
@@ -55,6 +55,7 @@
 
   -- * Unfolding
   unfoldr, unfoldrM,
+  unfoldrN, unfoldrNM,
 
   -- * Scans
   prescanl, prescanlM, prescanl', prescanlM',
@@ -66,7 +67,7 @@
   enumFromStepN, enumFromTo, enumFromThenTo,
 
   -- * Conversions
-  toList, fromList
+  toList, fromList, fromListN, unsafeFromList
 ) where
 
 import Data.Vector.Fusion.Stream.Size
@@ -87,7 +88,6 @@
                         and, or,
                         scanl, scanl1,
                         enumFromTo, enumFromThenTo )
-import qualified Prelude
 
 import Data.Int  ( Int8, Int16, Int32, Int64 )
 import Data.Word ( Word8, Word16, Word32, Word, Word64 )
@@ -155,14 +155,20 @@
 
 -- | Replicate a value to a given length
 replicate :: Monad m => Int -> a -> Stream m a
-{-# INLINE_STREAM replicate #-}
+{-# INLINE replicate #-}
+replicate n x = replicateM n (return x)
+
+-- | Yield a 'Stream' of values obtained by performing the monadic action the
+-- given number of times
+replicateM :: Monad m => Int -> m a -> Stream m a
+{-# INLINE_STREAM replicateM #-}
 -- NOTE: We delay inlining max here because GHC will create a join point for
 -- the call to newArray# otherwise which is not really nice.
-replicate n x = Stream (return . step) n (Exact (delay_inline max n 0))
+replicateM n p = Stream step n (Exact (delay_inline max n 0))
   where
     {-# INLINE_INNER step #-}
-    step i | i <= 0    = Done
-           | otherwise = Yield x (i-1)
+    step i | i <= 0    = return Done
+           | otherwise = do { x <- p; return $ Yield x (i-1) }
 
 generate :: Monad m => Int -> (Int -> a) -> Stream m a
 {-# INLINE generate #-}
@@ -377,19 +383,23 @@
                   Skip    s' -> return (Skip    s')
                   Done       -> return Done
 
--- | Execute a monadic action for each element of the 'Stream'
-mapM_ :: Monad m => (a -> m b) -> Stream m a -> m ()
-{-# INLINE_STREAM mapM_ #-}
-mapM_ m (Stream step s _) = mapM_loop SPEC s
+consume :: Monad m => Stream m a -> m ()
+{-# INLINE_STREAM consume #-}
+consume (Stream step s _) = consume_loop SPEC s
   where
-    mapM_loop SPEC s
+    consume_loop SPEC s
       = do
           r <- step s
           case r of
-            Yield x s' -> do { m x; mapM_loop SPEC s' }
-            Skip    s' -> mapM_loop SPEC s'
+            Yield _ s' -> consume_loop SPEC s'
+            Skip    s' -> consume_loop SPEC s'
             Done       -> return ()
 
+-- | Execute a monadic action for each element of the 'Stream'
+mapM_ :: Monad m => (a -> m b) -> Stream m a -> m ()
+{-# INLINE_STREAM mapM_ #-}
+mapM_ m = consume . mapM m
+
 -- | Transform a 'Stream' to use a different monad
 trans :: (Monad m, Monad m') => (forall a. m a -> m' a)
                              -> Stream m a -> Stream m' a
@@ -474,6 +484,10 @@
 
   #-}
 
+zipWithM_ :: Monad m => (a -> b -> m c) -> Stream m a -> Stream m b -> m ()
+{-# INLINE zipWithM_ #-}
+zipWithM_ f sa sb = consume (zipWithM f sa sb)
+
 zipWith3M :: Monad m => (a -> b -> c -> m d) -> Stream m a -> Stream m b -> Stream m c -> Stream m d
 {-# INLINE_STREAM zipWith3M #-}
 zipWith3M f (Stream stepa sa na) (Stream stepb sb nb) (Stream stepc sc nc)
@@ -937,6 +951,24 @@
                  Nothing      -> Done
              ) (f s)
 
+-- | Unfold at most @n@ elements
+unfoldrN :: Monad m => Int -> (s -> Maybe (a, s)) -> s -> Stream m a
+{-# INLINE_STREAM unfoldrN #-}
+unfoldrN n f = unfoldrNM n (return . f)
+
+-- | Unfold at most @n@ elements with a monadic functions
+unfoldrNM :: Monad m => Int -> (s -> m (Maybe (a, s))) -> s -> Stream m a
+{-# INLINE_STREAM unfoldrNM #-}
+unfoldrNM n f s = Stream step (s,n) (Max (delay_inline max n 0))
+  where
+    {-# INLINE_INNER step #-}
+    step (s,n) | n <= 0    = return Done
+               | otherwise = liftM (\r ->
+                               case r of
+                                 Just (x,s') -> Yield x (s',n-1)
+                                 Nothing     -> Done
+                             ) (f s)
+
 -- Scans
 -- -----
 
@@ -1123,9 +1155,6 @@
 {-# INLINE_STREAM enumFromTo #-}
 enumFromTo x y = fromList [x .. y]
 
--- FIXME: Specialise enumFromTo for Float and Double. Also, try to do
--- something about pairs?
-
 -- NOTE: We use (x+1) instead of (succ x) below because the latter checks for
 -- overflow which can't happen here.
 
@@ -1268,7 +1297,7 @@
                         $ fromIntegral n
       where
         n = y-x+1
-                        
+
     {-# INLINE_INNER step #-}
     step x | x <= y    = return $ Yield x (x+1)
            | otherwise = return $ Done
@@ -1304,6 +1333,41 @@
 
   #-}
 
+------------------------------------------------------------------------
+
+-- Specialise enumFromTo for Float and Double.
+-- Also, try to do something about pairs?
+
+enumFromTo_double :: (Monad m, Ord a, RealFrac a) => a -> a -> Stream m a
+{-# INLINE_STREAM enumFromTo_double #-}
+enumFromTo_double n m = Stream step n (Max (len n m))
+  where
+    lim = m + 1/2 -- important to float out
+
+    {-# INLINE [0] len #-}
+    len x y | x > y     = 0
+            | otherwise = BOUNDS_CHECK(check) "enumFromTo" "vector too large"
+                          (n > 0)
+                        $ fromIntegral n
+      where
+        n = truncate (y-x)+2
+
+    {-# INLINE_INNER step #-}
+    step x | x <= lim  = return $ Yield x (x+1)
+           | otherwise = return $ Done
+
+{-# RULES
+
+"enumFromTo<Double> [Stream]"
+  enumFromTo = enumFromTo_double :: Monad m => Double -> Double -> Stream m Double
+
+"enumFromTo<Float> [Stream]"
+  enumFromTo = enumFromTo_double :: Monad m => Float -> Float -> Stream m Float
+
+  #-}
+
+------------------------------------------------------------------------
+
 -- | Enumerate values with a given step.
 --
 -- /WARNING:/ This operation is very inefficient. If at all possible, use
@@ -1324,8 +1388,23 @@
 
 -- | Convert a list to a 'Stream'
 fromList :: Monad m => [a] -> Stream m a
-{-# INLINE_STREAM fromList #-}
-fromList xs = Stream step xs Unknown
+{-# INLINE fromList #-}
+fromList xs = unsafeFromList Unknown xs
+
+-- | Convert the first @n@ elements of a list to a 'Stream'
+fromListN :: Monad m => Int -> [a] -> Stream m a
+{-# INLINE_STREAM fromListN #-}
+fromListN n xs = Stream step (xs,n) (Max (delay_inline max n 0))
+  where
+    {-# INLINE_INNER step #-}
+    step (xs,n) | n <= 0 = return Done
+    step (x:xs,n)        = return (Yield x (xs,n-1))
+    step ([],n)          = return Done
+
+-- | Convert a list to a 'Stream' with the given 'Size' hint. 
+unsafeFromList :: Monad m => Size -> [a] -> Stream m a
+{-# INLINE_STREAM unsafeFromList #-}
+unsafeFromList sz xs = Stream step xs sz
   where
     step (x:xs) = return (Yield x xs)
     step []     = return Done
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,13 +1,13 @@
 -- |
 -- Module      : Data.Vector.Fusion.Stream.Size
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
 -- Stability   : experimental
 -- Portability : portable
 -- 
--- Size hints
+-- Size hints for streams.
 --
 
 module Data.Vector.Fusion.Stream.Size (
diff --git a/Data/Vector/Generic.hs b/Data/Vector/Generic.hs
--- a/Data/Vector/Generic.hs
+++ b/Data/Vector/Generic.hs
@@ -2,7 +2,7 @@
              TypeFamilies, ScopedTypeVariables #-}
 -- |
 -- Module      : Data.Vector.Generic
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -20,7 +20,7 @@
   length, null,
 
   -- * Construction
-  empty, singleton, cons, snoc, replicate, generate, (++), copy,
+  empty, singleton, cons, snoc, replicate, generate, (++), force,
 
   -- * Accessing individual elements
   (!), head, last, indexM, headM, lastM,
@@ -69,7 +69,7 @@
   minIndex, minIndexBy, maxIndex, maxIndexBy,
 
   -- * Unfolding
-  unfoldr,
+  unfoldr, unfoldrN,
 
   -- * Scans
   prescanl, prescanl',
@@ -83,15 +83,27 @@
   enumFromN, enumFromStepN, enumFromTo, enumFromThenTo,
 
   -- * Conversion to/from lists
-  toList, fromList,
+  toList, fromList, fromListN,
 
+  -- * Monadic operations
+  replicateM, mapM, mapM_, forM, forM_, zipWithM, zipWithM_, filterM,
+  foldM, foldM', fold1M, fold1M',
+
+  -- * Destructive operations
+  create, modify, copy, unsafeCopy,
+
   -- * Conversion to/from Streams
   stream, unstream, streamR, unstreamR,
 
-  -- * MVector-based initialisation
-  new
+  -- * Recycling support
+  new, clone,
+
+  -- * Utilities for defining Data instances
+  gfoldl, dataCast, mkType
 ) where
 
+import           Data.Vector.Generic.Base
+
 import           Data.Vector.Generic.Mutable ( MVector )
 import qualified Data.Vector.Generic.Mutable as M
 
@@ -104,8 +116,9 @@
 import           Data.Vector.Fusion.Stream.Size
 import           Data.Vector.Fusion.Util
 
-import Control.Monad.ST ( runST )
+import Control.Monad.ST ( ST, runST )
 import Control.Monad.Primitive
+import qualified Control.Monad as Monad
 import Prelude hiding ( length, null,
                         replicate, (++),
                         head, last,
@@ -117,71 +130,29 @@
                         foldl, foldl1, foldr, foldr1,
                         all, any, and, or, sum, product, maximum, minimum,
                         scanl, scanl1, scanr, scanr1,
-                        enumFromTo, enumFromThenTo )
-
-#include "vector.h"
-
-type family Mutable (v :: * -> *) :: * -> * -> *
-
--- | Class of immutable vectors.
---
-class MVector (Mutable v) a => Vector v a where
-  -- | Unsafely convert a mutable vector to its immutable version
-  -- without copying. The mutable vector may not be used after
-  -- this operation.
-  unsafeFreeze :: PrimMonad m => Mutable v (PrimState m) a -> m (v a)
-
-  -- | Length of the vector (not fusible!)
-  basicLength      :: v a -> Int
-
-  -- | Yield a part of the vector without copying it. No range checks!
-  basicUnsafeSlice  :: Int -> Int -> v a -> 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 'basicUnsafeIndexM', we can do
-  --
-  -- > copy mv v ... = ... case basicUnsafeIndexM 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.
-  --
-  basicUnsafeIndexM  :: Monad m => v a -> Int -> m a
+                        enumFromTo, enumFromThenTo,
+                        mapM, mapM_ )
 
-  elemseq :: v a -> a -> b -> b
+import Data.Typeable ( Typeable1, gcast1 )
+import Data.Data ( Data, DataType, mkNorepType )
 
-  {-# INLINE elemseq #-}
-  elemseq _ = \_ x -> x
+#include "vector.h"
 
 -- Fusion
 -- ------
 
 -- | Construct a pure vector from a monadic initialiser 
-new :: Vector v a => New a -> v a
-{-# INLINE new #-}
-new m = new' undefined m
+new :: Vector v a => New v a -> v a
+{-# INLINE_STREAM new #-}
+new m = m `seq` runST (unsafeFreeze =<< New.run 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 = m `seq` runST (do
-                            mv <- New.run m
-                            unsafeFreeze mv)
+clone :: Vector v a => v a -> New v a
+{-# INLINE_STREAM clone #-}
+clone v = v `seq` New.create (
+  do
+    mv <- M.new (length v)
+    unsafeCopy mv v
+    return mv)
 
 -- | Convert a vector to a 'Stream'
 stream :: Vector v a => v a -> Stream a
@@ -203,23 +174,22 @@
 
 {-# 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
+"stream/unstream [Vector]" forall s.
+  stream (new (New.unstream s)) = s
 
- #-}
+"New.unstream/stream [Vector]" forall v.
+  New.unstream (stream v) = clone v
 
-{-# RULES
+"clone/new [Vector]" forall p.
+  clone (new p) = p
 
 "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
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a) m.
+  New.unstream (inplace f (stream (new 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))
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a) m.
+  stream (new (New.transform f m)) = inplace f (stream (new m))
 
  #-}
 
@@ -230,8 +200,6 @@
   where
     n = length v
 
-    -- NOTE: the False case comes first in Core so making it the recursive one
-    -- makes the code easier to read
     {-# INLINE get #-}
     get 0 = Nothing
     get i = let i' = i-1
@@ -245,23 +213,19 @@
 
 {-# RULES
 
-"streamR/unstreamR [Vector]" forall v s.
-  streamR (new' v (New.unstreamR s)) = s
-
-"New.unstreamR/streamR/new [Vector]" forall v p.
-  New.unstreamR (streamR (new' v p)) = p
-
- #-}
+"streamR/unstreamR [Vector]" forall s.
+  streamR (new (New.unstreamR s)) = s
 
-{-# RULES
+"New.unstreamR/streamR/new [Vector]" forall p.
+  New.unstreamR (streamR (new p)) = p
 
-"inplace [Vector]"
-  forall (f :: forall m. Monad m => MStream m a -> MStream m a) v m.
-  New.unstreamR (inplace f (streamR (new' v m))) = New.transformR f m
+"inplace right [Vector]"
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a) m.
+  New.unstreamR (inplace f (streamR (new m))) = New.transformR f m
 
-"uninplace [Vector]"
-  forall (f :: forall m. Monad m => MStream m a -> MStream m a) v m.
-  streamR (new' v (New.transformR f m)) = inplace f (streamR (new' v m))
+"uninplace right [Vector]"
+  forall (f :: forall m. Monad m => MStream m a -> MStream m a) m.
+  streamR (new (New.transformR f m)) = inplace f (streamR (new m))
 
  #-}
 
@@ -274,15 +238,22 @@
 
 {-# RULES
 
-"length/unstream [Vector]" forall v s.
-  length (new' v (New.unstream s)) = Stream.length s
+"length/unstream [Vector]" forall s.
+  length (new (New.unstream s)) = Stream.length s
 
   #-}
 
 null :: Vector v a => v a -> Bool
-{-# INLINE null #-}
-null v = length v == 0
+{-# INLINE_STREAM null #-}
+null v = basicLength v == 0
 
+{-# RULES
+
+"null/unstream [Vector]" forall s.
+  null (new (New.unstream s)) = Stream.null s
+
+  #-}
+
 -- Construction
 -- ------------
 
@@ -332,16 +303,9 @@
 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)
-
- #-}
+force :: Vector v a => v a -> v a
+{-# INLINE_STREAM force #-}
+force v = new (clone v)
 
 -- Accessing individual elements
 -- -----------------------------
@@ -382,23 +346,23 @@
 
 {-# RULES
 
-"(!)/unstream [Vector]" forall v i s.
-  new' v (New.unstream s) ! i = s Stream.!! i
+"(!)/unstream [Vector]" forall i s.
+  new (New.unstream s) ! i = s Stream.!! i
 
-"head/unstream [Vector]" forall v s.
-  head (new' v (New.unstream s)) = Stream.head s
+"head/unstream [Vector]" forall s.
+  head (new (New.unstream s)) = Stream.head s
 
-"last/unstream [Vector]" forall v s.
-  last (new' v (New.unstream s)) = Stream.last s
+"last/unstream [Vector]" forall s.
+  last (new (New.unstream s)) = Stream.last s
 
-"unsafeIndex/unstream [Vector]" forall v i s.
-  unsafeIndex (new' v (New.unstream s)) i = s Stream.!! i
+"unsafeIndex/unstream [Vector]" forall i s.
+  unsafeIndex (new (New.unstream s)) i = s Stream.!! i
 
-"unsafeHead/unstream [Vector]" forall v s.
-  unsafeHead (new' v (New.unstream s)) = Stream.head s
+"unsafeHead/unstream [Vector]" forall s.
+  unsafeHead (new (New.unstream s)) = Stream.head s
 
-"unsafeLast/unstream [Vector]" forall v s.
-  unsafeLast (new' v (New.unstream s)) = Stream.last s
+"unsafeLast/unstream [Vector]" forall s.
+  unsafeLast (new (New.unstream s)) = Stream.last s
 
  #-}
 
@@ -448,8 +412,6 @@
 -- Subarrays
 -- ---------
 
--- FIXME: slicing doesn't work with the inplace stuff at the moment
-
 -- | Yield a part of the vector without copying it.
 slice :: Vector v a => Int   -- ^ starting index
                     -> Int   -- ^ length
@@ -511,29 +473,29 @@
 
 {-# RULES
 
-"slice/new [Vector]" forall i n v p.
-  slice i n (new' v p) = new' v (New.slice i n p)
+"slice/new [Vector]" forall i n p.
+  slice i n (new p) = new (New.slice i n p)
 
-"init/new [Vector]" forall v p.
-  init (new' v p) = new' v (New.init p)
+"init/new [Vector]" forall p.
+  init (new p) = new (New.init p)
 
-"tail/new [Vector]" forall v p.
-  tail (new' v p) = new' v (New.tail p)
+"tail/new [Vector]" forall p.
+  tail (new p) = new (New.tail p)
 
-"take/new [Vector]" forall n v p.
-  take n (new' v p) = new' v (New.take n p)
+"take/new [Vector]" forall n p.
+  take n (new p) = new (New.take n p)
 
-"drop/new [Vector]" forall n v p.
-  drop n (new' v p) = new' v (New.drop n p)
+"drop/new [Vector]" forall n p.
+  drop n (new p) = new (New.drop n p)
 
-"unsafeSlice/new [Vector]" forall i n v p.
-  unsafeSlice i n (new' v p) = new' v (New.unsafeSlice i n p)
+"unsafeSlice/new [Vector]" forall i n p.
+  unsafeSlice i n (new p) = new (New.unsafeSlice i n p)
 
-"unsafeInit/new [Vector]" forall v p.
-  unsafeInit (new' v p) = new' v (New.unsafeInit p)
+"unsafeInit/new [Vector]" forall p.
+  unsafeInit (new p) = new (New.unsafeInit p)
 
-"unsafeTail/new [Vector]" forall v p.
-  unsafeTail (new' v p) = new' v (New.unsafeTail p)
+"unsafeTail/new [Vector]" forall p.
+  unsafeTail (new p) = new (New.unsafeTail p)
 
   #-}
 
@@ -543,7 +505,7 @@
 unsafeAccum_stream
   :: Vector v a => (a -> b -> a) -> v a -> Stream (Int,b) -> v a
 {-# INLINE unsafeAccum_stream #-}
-unsafeAccum_stream f v s = new (New.accum f (New.unstream (stream v)) s)
+unsafeAccum_stream f = modifyWithStream (M.unsafeAccum f)
 
 unsafeAccum :: Vector v a => (a -> b -> a) -> v a -> [(Int,b)] -> v a
 {-# INLINE unsafeAccum #-}
@@ -562,7 +524,7 @@
 
 accum_stream :: Vector v a => (a -> b -> a) -> v a -> Stream (Int,b) -> v a
 {-# INLINE accum_stream #-}
-accum_stream f v s = new (New.accum f (New.unstream (stream v)) s)
+accum_stream f = modifyWithStream (M.accum f)
 
 accum :: Vector v a => (a -> b -> a) -> v a -> [(Int,b)] -> v a
 {-# INLINE accum #-}
@@ -582,7 +544,7 @@
 
 unsafeUpdate_stream :: Vector v a => v a -> Stream (Int,a) -> v a
 {-# INLINE unsafeUpdate_stream #-}
-unsafeUpdate_stream v s = new (New.unsafeUpdate (New.unstream (stream v)) s)
+unsafeUpdate_stream = modifyWithStream M.unsafeUpdate
 
 unsafeUpd :: Vector v a => v a -> [(Int, a)] -> v a
 {-# INLINE unsafeUpd #-}
@@ -599,7 +561,7 @@
 
 update_stream :: Vector v a => v a -> Stream (Int,a) -> v a
 {-# INLINE update_stream #-}
-update_stream v s = new (New.update (New.unstream (stream v)) s)
+update_stream = modifyWithStream M.update
 
 (//) :: Vector v a => v a -> [(Int, a)] -> v a
 {-# INLINE (//) #-}
@@ -634,9 +596,10 @@
                        $ Stream.map (unsafeIndexM v)
                        $ stream is
 
+-- FIXME: make this fuse better, add support for recycling
 reverse :: (Vector v a) => v a -> v a
 {-# INLINE reverse #-}
-reverse = new . New.reverse . New.unstream . stream
+reverse = unstream . streamR
 
 -- Mapping
 -- -------
@@ -901,7 +864,7 @@
     v2 <- unsafeFreeze mv2
     return (v1,v2))
 
-unstablePartition_new :: Vector v a => (a -> Bool) -> New a -> (v a, v a)
+unstablePartition_new :: Vector v a => (a -> Bool) -> New v a -> (v a, v a)
 {-# INLINE_STREAM unstablePartition_new #-}
 unstablePartition_new f (New.New p) = runST (
   do
@@ -912,8 +875,8 @@
 
 {-# RULES
 
-"unstablePartition" forall f v p.
-  unstablePartition_stream f (stream (new' v p))
+"unstablePartition" forall f p.
+  unstablePartition_stream f (stream (new p))
     = unstablePartition_new f p
 
   #-}
@@ -1129,10 +1092,16 @@
 -- Unfolding
 -- ---------
 
+-- | Unfold
 unfoldr :: Vector v a => (b -> Maybe (a, b)) -> b -> v a
 {-# INLINE unfoldr #-}
 unfoldr f = unstream . Stream.unfoldr f
 
+-- | Unfoldr at most @n@ elements.
+unfoldrN  :: Vector v a => Int -> (b -> Maybe (a, b)) -> b -> v a
+{-# INLINE unfoldrN #-}
+unfoldrN n f = unstream . Stream.unfoldrN n f
+
 -- Scans
 -- -----
 
@@ -1252,6 +1221,9 @@
 {-# INLINE enumFromThenTo #-}
 enumFromThenTo x y z = unstream (Stream.enumFromThenTo x y z)
 
+-- Conversion to/from lists
+-- ------------------------
+
 -- | Convert a vector to a list
 toList :: Vector v a => v a -> [a]
 {-# INLINE toList #-}
@@ -1261,4 +1233,151 @@
 fromList :: Vector v a => [a] -> v a
 {-# INLINE fromList #-}
 fromList = unstream . Stream.fromList
+
+-- | Convert the first @n@ elements of a list to a vector
+--
+-- > fromListN n xs = fromList (take n xs)
+fromListN :: Vector v a => Int -> [a] -> v a
+{-# INLINE fromListN #-}
+fromListN n = unstream . Stream.fromListN n
+
+unstreamM :: (Vector v a, Monad m) => MStream m a -> m (v a)
+{-# INLINE_STREAM unstreamM #-}
+unstreamM s = do
+                xs <- MStream.toList s
+                return $ unstream $ Stream.unsafeFromList (MStream.size s) xs
+
+-- Monadic operations
+-- ------------------
+
+-- FIXME: specialise various combinators for ST and IO?
+
+-- | Perform the monadic action the given number of times and store the
+-- results in a vector.
+replicateM :: (Monad m, Vector v a) => Int -> m a -> m (v a)
+{-# INLINE replicateM #-}
+replicateM n m = fromListN n `Monad.liftM` Monad.replicateM n m
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+mapM :: (Monad m, Vector v a, Vector v b) => (a -> m b) -> v a -> m (v b)
+{-# INLINE mapM #-}
+mapM f = unstreamM . Stream.mapM f . stream
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+mapM_ :: (Monad m, Vector v a) => (a -> m b) -> v a -> m ()
+{-# INLINE mapM_ #-}
+mapM_ f = Stream.mapM_ f . stream
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+forM :: (Monad m, Vector v a, Vector v b) => v a -> (a -> m b) -> m (v b)
+{-# INLINE forM #-}
+forM as f = mapM f as
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+forM_ :: (Monad m, Vector v a) => v a -> (a -> m b) -> m ()
+{-# INLINE forM_ #-}
+forM_ as f = mapM_ f as
+
+-- | Zip the two vectors with the monadic action and yield a vector of results
+zipWithM :: (Monad m, Vector v a, Vector v b, Vector v c)
+         => (a -> b -> m c) -> v a -> v b -> m (v c)
+{-# INLINE zipWithM #-}
+zipWithM f as bs = unstreamM $ Stream.zipWithM f (stream as) (stream bs)
+
+-- | Zip the two vectors with the monadic action and ignore the results
+zipWithM_ :: (Monad m, Vector v a, Vector v b)
+          => (a -> b -> m c) -> v a -> v b -> m ()
+{-# INLINE zipWithM_ #-}
+zipWithM_ f as bs = Stream.zipWithM_ f (stream as) (stream bs)
+
+-- | Drop elements that do not satisfy the monadic predicate
+filterM :: (Monad m, Vector v a) => (a -> m Bool) -> v a -> m (v a)
+{-# INLINE filterM #-}
+filterM f = unstreamM . Stream.filterM f . stream
+
+-- | Monadic fold
+foldM :: (Monad m, Vector v b) => (a -> b -> m a) -> a -> v b -> m a
+{-# INLINE foldM #-}
+foldM m z = Stream.foldM m z . stream
+
+-- | Monadic fold over non-empty vectors
+fold1M :: (Monad m, Vector v a) => (a -> a -> m a) -> v a -> m a
+{-# INLINE fold1M #-}
+fold1M m = Stream.fold1M m . stream
+
+-- | Monadic fold with strict accumulator
+foldM' :: (Monad m, Vector v b) => (a -> b -> m a) -> a -> v b -> m a
+{-# INLINE foldM' #-}
+foldM' m z = Stream.foldM' m z . stream
+
+-- | Monad fold over non-empty vectors with strict accumulator
+fold1M' :: (Monad m, Vector v a) => (a -> a -> m a) -> v a -> m a
+{-# INLINE fold1M' #-}
+fold1M' m = Stream.fold1M' m . stream
+
+-- Destructive operations
+-- ----------------------
+
+-- | Destructively initialise a vector.
+create :: Vector v a => (forall s. ST s (Mutable v s a)) -> v a
+{-# INLINE create #-}
+create p = new (New.create p)
+
+-- | Apply a destructive operation to a vector. The operation modifies a
+-- copy of the vector unless it can be safely performed in place.
+modify :: Vector v a => (forall s. Mutable v s a -> ST s ()) -> v a -> v a
+{-# INLINE modify #-}
+modify p = new . New.modify p . clone
+
+-- We have to make sure that this is strict in the stream but we can't seq on
+-- it while fusion is happening. Hence this ugliness.
+modifyWithStream :: Vector v a
+                 => (forall s. Mutable v s a -> Stream b -> ST s ())
+                 -> v a -> Stream b -> v a
+{-# INLINE modifyWithStream #-}
+modifyWithStream p v s = new (New.modifyWithStream p (clone v) s)
+
+-- | Copy an immutable vector into a mutable one. The two vectors must have
+-- the same length. This is not checked.
+unsafeCopy
+  :: (PrimMonad m, Vector v a) => Mutable v (PrimState m) a -> v a -> m ()
+{-# INLINE unsafeCopy #-}
+unsafeCopy dst src = UNSAFE_CHECK(check) "unsafeCopy" "length mismatch"
+                                         (M.length dst == length src)
+                   $ (dst `seq` src `seq` basicUnsafeCopy dst src)
+           
+-- | Copy an immutable vector into a mutable one. The two vectors must have the
+-- same length.
+copy
+  :: (PrimMonad m, Vector v a) => Mutable v (PrimState m) a -> v a -> m ()
+{-# INLINE copy #-}
+copy dst src = BOUNDS_CHECK(check) "copy" "length mismatch"
+                                          (M.length dst == length src)
+             $ unsafeCopy dst src
+
+-- Utilities for defining Data instances
+-- -------------------------------------
+
+-- | Generic definion of 'Data.Data.gfoldl' that views a 'Vector' as a
+-- list.
+gfoldl :: (Vector v a, Data a)
+       => (forall d b. Data d => c (d -> b) -> d -> c b)
+       -> (forall g. g -> c g)
+       -> v a
+       -> c (v a)
+{-# INLINE gfoldl #-}
+gfoldl f z v = z fromList `f` toList v
+
+mkType :: String -> DataType
+{-# INLINE mkType #-}
+mkType = mkNorepType
+
+dataCast :: (Vector v a, Data a, Typeable1 v, Typeable1 t)
+         => (forall d. Data  d => c (t d)) -> Maybe  (c (v a))
+{-# INLINE dataCast #-}
+dataCast f = gcast1 f
 
diff --git a/Data/Vector/Generic/Base.hs b/Data/Vector/Generic/Base.hs
new file mode 100644
--- /dev/null
+++ b/Data/Vector/Generic/Base.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE Rank2Types, MultiParamTypeClasses, FlexibleContexts,
+             TypeFamilies, ScopedTypeVariables #-}
+
+-- |
+-- Module      : Data.Vector.Generic.Base
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable
+-- 
+-- Class of pure vectors
+--
+
+module Data.Vector.Generic.Base (
+  Vector(..), Mutable
+) where
+
+import           Data.Vector.Generic.Mutable ( MVector )
+import qualified Data.Vector.Generic.Mutable as M
+
+import Control.Monad.Primitive
+
+-- | @Mutable v s a@ is the mutable version of the pure vector type @v a@ with
+-- the state token @s@
+--
+type family Mutable (v :: * -> *) :: * -> * -> *
+
+-- | Class of immutable vectors.
+--
+class MVector (Mutable v) a => Vector v a where
+  -- | Unsafely convert a mutable vector to its immutable version
+  -- without copying. The mutable vector may not be used after
+  -- this operation.
+  unsafeFreeze :: PrimMonad m => Mutable v (PrimState m) a -> m (v a)
+
+  -- | Length of the vector (not fusible!)
+  basicLength      :: v a -> Int
+
+  -- | Yield a part of the vector without copying it. No range checks!
+  basicUnsafeSlice  :: Int -> Int -> v a -> 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 'basicUnsafeIndexM', we can do
+  --
+  -- > copy mv v ... = ... case basicUnsafeIndexM 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.
+  --
+  basicUnsafeIndexM  :: Monad m => v a -> Int -> m a
+
+  -- | Copy an immutable vector into a mutable one.
+  basicUnsafeCopy :: PrimMonad m => Mutable v (PrimState m) a -> v a -> m ()
+
+  {-# INLINE basicUnsafeCopy #-}
+  basicUnsafeCopy dst src = do_copy 0
+    where
+      n = basicLength src
+
+      do_copy i | i < n = do
+                            x <- basicUnsafeIndexM src i
+                            M.basicUnsafeWrite dst i x
+                            do_copy (i+1)
+                | otherwise = return ()
+
+  elemseq :: v a -> a -> b -> b
+
+  {-# INLINE elemseq #-}
+  elemseq _ = \_ x -> x
+
+
diff --git a/Data/Vector/Generic/Mutable.hs b/Data/Vector/Generic/Mutable.hs
--- a/Data/Vector/Generic/Mutable.hs
+++ b/Data/Vector/Generic/Mutable.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE MultiParamTypeClasses, BangPatterns, ScopedTypeVariables #-}
 -- |
 -- Module      : Data.Vector.Generic.Mutable
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -26,7 +26,10 @@
   unsafeCopy, unsafeGrow,
 
   -- * Internal operations
-  unstream, transform, unstreamR, transformR,
+  unstream, unstreamR,
+  munstream, munstreamR,
+  transform, transformR,
+  fill, fillR,
   unsafeAccum, accum, unsafeUpdate, update, reverse,
   unstablePartition, unstablePartitionStream, partitionStream
 ) where
@@ -38,10 +41,6 @@
 
 import Control.Monad.Primitive ( PrimMonad, PrimState )
 
-import GHC.Float (
-    double2Int, int2Double
-  )
-
 import Prelude hiding ( length, reverse, map, read,
                         take, drop, init, tail )
 
@@ -194,27 +193,27 @@
                            return $ Just (x, i+1)
           | otherwise = return $ Nothing
 
-munstream :: (PrimMonad m, MVector v a)
+fill :: (PrimMonad m, MVector v a)
            => v (PrimState m) a -> MStream m a -> m (v (PrimState m) a)
-{-# INLINE munstream #-}
-munstream v s = v `seq` do
-                          n' <- MStream.foldM put 0 s
-                          return $ unsafeSlice 0 n' v
+{-# INLINE fill #-}
+fill v s = v `seq` do
+                     n' <- MStream.foldM put 0 s
+                     return $ unsafeSlice 0 n' v
   where
     {-# INLINE_INNER put #-}
     put i x = do
-                INTERNAL_CHECK(checkIndex) "munstream" i (length v)
+                INTERNAL_CHECK(checkIndex) "fill" i (length v)
                   $ unsafeWrite v i x
                 return (i+1)
 
 transform :: (PrimMonad m, MVector v a)
   => (MStream m a -> MStream m a) -> v (PrimState m) a -> m (v (PrimState m) a)
 {-# INLINE_STREAM transform #-}
-transform f v = munstream v (f (mstream v))
+transform f v = fill v (f (mstream v))
 
-mrstream :: (PrimMonad m, MVector v a) => v (PrimState m) a -> MStream m a
-{-# INLINE mrstream #-}
-mrstream v = v `seq` (MStream.unfoldrM get n `MStream.sized` Exact n)
+mstreamR :: (PrimMonad m, MVector v a) => v (PrimState m) a -> MStream m a
+{-# INLINE mstreamR #-}
+mstreamR v = v `seq` (MStream.unfoldrM get n `MStream.sized` Exact n)
   where
     n = length v
 
@@ -225,12 +224,12 @@
       where
         j = i-1
 
-munstreamR :: (PrimMonad m, MVector v a)
+fillR :: (PrimMonad m, MVector v a)
            => v (PrimState m) a -> MStream m a -> m (v (PrimState m) a)
-{-# INLINE munstreamR #-}
-munstreamR v s = v `seq` do
-                           i <- MStream.foldM put n s
-                           return $ unsafeSlice i (n-i) v
+{-# INLINE fillR #-}
+fillR v s = v `seq` do
+                      i <- MStream.foldM put n s
+                      return $ unsafeSlice i (n-i) v
   where
     n = length v
 
@@ -244,17 +243,25 @@
 transformR :: (PrimMonad m, MVector v a)
   => (MStream m a -> MStream m a) -> v (PrimState m) a -> m (v (PrimState m) a)
 {-# INLINE_STREAM transformR #-}
-transformR f v = munstreamR v (f (mrstream v))
+transformR f v = fillR v (f (mstreamR 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.
+-- The vector will grow exponentially if the maximum size of the 'Stream' is
+-- unknown.
 unstream :: (PrimMonad m, MVector v a) => Stream a -> m (v (PrimState m) a)
+-- NOTE: replace INLINE_STREAM by INLINE? (also in unstreamR)
 {-# INLINE_STREAM unstream #-}
-unstream s = case upperBound (Stream.size s) of
-               Just n  -> unstreamMax     s n
-               Nothing -> unstreamUnknown s
+unstream s = munstream (Stream.liftStream s)
 
+-- | Create a new mutable vector and fill it with elements from the monadic
+-- stream. The vector will grow exponentially if the maximum size of the stream
+-- is unknown.
+munstream :: (PrimMonad m, MVector v a) => MStream m a -> m (v (PrimState m) a)
+{-# INLINE_STREAM munstream #-}
+munstream s = case upperBound (MStream.size s) of
+               Just n  -> munstreamMax     s n
+               Nothing -> munstreamUnknown s
+
 -- FIXME: I can't think of how to prevent GHC from floating out
 -- unstreamUnknown. That is bad because SpecConstr then generates two
 -- specialisations: one for when it is called from unstream (it doesn't know
@@ -263,30 +270,31 @@
 --
 -- fromList = Data.Vector.Unboxed.unstream . Stream.fromList
 --
+-- I'm not sure this still applies (19/04/2010)
 
-unstreamMax
-  :: (PrimMonad m, MVector v a) => Stream a -> Int -> m (v (PrimState m) a)
-{-# INLINE unstreamMax #-}
-unstreamMax s n
+munstreamMax
+  :: (PrimMonad m, MVector v a) => MStream m a -> Int -> m (v (PrimState m) a)
+{-# INLINE munstreamMax #-}
+munstreamMax s n
   = do
-      v <- INTERNAL_CHECK(checkLength) "unstreamMax" n
+      v <- INTERNAL_CHECK(checkLength) "munstreamMax" n
            $ unsafeNew n
       let put i x = do
-                       INTERNAL_CHECK(checkIndex) "unstreamMax" i n
+                       INTERNAL_CHECK(checkIndex) "munstreamMax" i n
                          $ unsafeWrite v i x
                        return (i+1)
-      n' <- Stream.foldM' put 0 s
-      return $ INTERNAL_CHECK(checkSlice) "unstreamMax" 0 n' n
+      n' <- MStream.foldM' put 0 s
+      return $ INTERNAL_CHECK(checkSlice) "munstreamMax" 0 n' n
              $ unsafeSlice 0 n' v
 
-unstreamUnknown
-  :: (PrimMonad m, MVector v a) => Stream a -> m (v (PrimState m) a)
-{-# INLINE unstreamUnknown #-}
-unstreamUnknown s
+munstreamUnknown
+  :: (PrimMonad m, MVector v a) => MStream m a -> m (v (PrimState m) a)
+{-# INLINE munstreamUnknown #-}
+munstreamUnknown s
   = do
       v <- unsafeNew 0
-      (v', n) <- Stream.foldM put (v, 0) s
-      return $ INTERNAL_CHECK(checkSlice) "unstreamUnknown" 0 n (length v')
+      (v', n) <- MStream.foldM put (v, 0) s
+      return $ INTERNAL_CHECK(checkSlice) "munstreamUnknown" 0 n (length v')
              $ unsafeSlice 0 n v'
   where
     {-# INLINE_INNER put #-}
@@ -294,38 +302,46 @@
                     v' <- unsafeAppend1 v i x
                     return (v',i+1)
 
--- | 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.
+-- | Create a new mutable vector and fill it with elements from the 'Stream'
+-- from right to left. The vector will grow exponentially if the maximum size
+-- of the 'Stream' is unknown.
 unstreamR :: (PrimMonad m, MVector v a) => Stream a -> m (v (PrimState m) a)
+-- NOTE: replace INLINE_STREAM by INLINE? (also in unstream)
 {-# INLINE_STREAM unstreamR #-}
-unstreamR s = case upperBound (Stream.size s) of
-               Just n  -> unstreamRMax     s n
-               Nothing -> unstreamRUnknown s
+unstreamR s = munstreamR (Stream.liftStream s)
 
-unstreamRMax
-  :: (PrimMonad m, MVector v a) => Stream a -> Int -> m (v (PrimState m) a)
-{-# INLINE unstreamRMax #-}
-unstreamRMax s n
+-- | Create a new mutable vector and fill it with elements from the monadic
+-- stream from right to left. The vector will grow exponentially if the maximum
+-- size of the stream is unknown.
+munstreamR :: (PrimMonad m, MVector v a) => MStream m a -> m (v (PrimState m) a)
+{-# INLINE_STREAM munstreamR #-}
+munstreamR s = case upperBound (MStream.size s) of
+               Just n  -> munstreamRMax     s n
+               Nothing -> munstreamRUnknown s
+
+munstreamRMax
+  :: (PrimMonad m, MVector v a) => MStream m a -> Int -> m (v (PrimState m) a)
+{-# INLINE munstreamRMax #-}
+munstreamRMax s n
   = do
-      v <- INTERNAL_CHECK(checkLength) "unstreamRMax" n
+      v <- INTERNAL_CHECK(checkLength) "munstreamRMax" n
            $ unsafeNew n
       let put i x = do
                       let i' = i-1
-                      INTERNAL_CHECK(checkIndex) "unstreamRMax" i' n
+                      INTERNAL_CHECK(checkIndex) "munstreamRMax" i' n
                         $ unsafeWrite v i' x
                       return i'
-      i <- Stream.foldM' put n s
-      return $ INTERNAL_CHECK(checkSlice) "unstreamRMax" i (n-i) n
+      i <- MStream.foldM' put n s
+      return $ INTERNAL_CHECK(checkSlice) "munstreamRMax" i (n-i) n
              $ unsafeSlice i (n-i) v
 
-unstreamRUnknown
-  :: (PrimMonad m, MVector v a) => Stream a -> m (v (PrimState m) a)
-{-# INLINE unstreamRUnknown #-}
-unstreamRUnknown s
+munstreamRUnknown
+  :: (PrimMonad m, MVector v a) => MStream m a -> m (v (PrimState m) a)
+{-# INLINE munstreamRUnknown #-}
+munstreamRUnknown s
   = do
       v <- unsafeNew 0
-      (v', i) <- Stream.foldM put (v, 0) s
+      (v', i) <- MStream.foldM put (v, 0) s
       let n = length v'
       return $ INTERNAL_CHECK(checkSlice) "unstreamRUnknown" i (n-i) n
              $ unsafeSlice i (n-i) v'
@@ -528,7 +544,7 @@
                                          (length dst == length src)
                    $ UNSAFE_CHECK(check) "unsafeCopy" "overlapping vectors"
                                          (not (dst `overlaps` src))
-                   $ basicUnsafeCopy dst src
+                   $ (dst `seq` src `seq` basicUnsafeCopy dst src)
 
 -- Subvectors
 -- ----------
diff --git a/Data/Vector/Generic/New.hs b/Data/Vector/Generic/New.hs
--- a/Data/Vector/Generic/New.hs
+++ b/Data/Vector/Generic/New.hs
@@ -2,7 +2,7 @@
 
 -- |
 -- Module      : Data.Vector.Generic.New
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -13,16 +13,17 @@
 --
 
 module Data.Vector.Generic.New (
-  New(..), run, unstream, transform, unstreamR, transformR,
-  accum, update, reverse,
+  New(..), create, run, apply, modify, modifyWithStream,
+  unstream, transform, unstreamR, transformR,
   slice, init, tail, take, drop,
-  unsafeSlice, unsafeInit, unsafeTail,
-  unsafeAccum, unsafeUpdate
+  unsafeSlice, unsafeInit, unsafeTail
 ) where
 
 import qualified Data.Vector.Generic.Mutable as MVector
 import           Data.Vector.Generic.Mutable ( MVector )
 
+import           Data.Vector.Generic.Base ( Vector, Mutable )
+
 import           Data.Vector.Fusion.Stream ( Stream, MStream )
 import qualified Data.Vector.Fusion.Stream as Stream
 
@@ -32,25 +33,35 @@
 
 #include "vector.h"
 
-data New a = New (forall mv s. MVector mv a => ST s (mv s a))
+data New v a = New (forall s. ST s (Mutable v s a))
 
-run :: MVector mv a => New a -> ST s (mv s a)
+create :: (forall s. ST s (Mutable v s a)) -> New v a
+{-# INLINE create #-}
+create = New
+
+run :: New v a -> ST s (Mutable v s a)
 {-# INLINE run #-}
 run (New p) = p
 
-apply :: (forall mv s a. MVector mv a => mv s a -> mv s a) -> New a -> New a
+apply :: (forall s. Mutable v s a -> Mutable v s a) -> New v a -> New v a
 {-# INLINE apply #-}
 apply f (New p) = New (liftM f p)
 
-modify :: New a -> (forall mv s. MVector mv a => mv s a -> ST s ()) -> New a
+modify :: (forall s. Mutable v s a -> ST s ()) -> New v a -> New v a
 {-# INLINE modify #-}
-modify (New p) q = New (do { v <- p; q v; return v })
+modify f (New p) = New (do { v <- p; f v; return v })
 
-unstream :: Stream a -> New a
+modifyWithStream :: (forall s. Mutable v s a -> Stream b -> ST s ())
+                 -> New v a -> Stream b -> New v a
+{-# INLINE_STREAM modifyWithStream #-}
+modifyWithStream f (New p) s = s `seq` New (do { v <- p; f v s; return v })
+
+unstream :: Vector v a => Stream a -> New v a
 {-# INLINE_STREAM unstream #-}
 unstream s = s `seq` New (MVector.unstream s)
 
-transform :: (forall m. Monad m => MStream m a -> MStream m a) -> New a -> New a
+transform :: Vector v a =>
+        (forall m. Monad m => MStream m a -> MStream m a) -> New v a -> New v a
 {-# INLINE_STREAM transform #-}
 transform f (New p) = New (MVector.transform f =<< p)
 
@@ -70,11 +81,12 @@
  #-}
 
 
-unstreamR :: Stream a -> New a
+unstreamR :: Vector v a => Stream a -> New v a
 {-# INLINE_STREAM unstreamR #-}
 unstreamR s = s `seq` New (MVector.unstreamR s)
 
-transformR :: (forall m. Monad m => MStream m a -> MStream m a) -> New a -> New a
+transformR :: Vector v a =>
+        (forall m. Monad m => MStream m a -> MStream m a) -> New v a -> New v a
 {-# INLINE_STREAM transformR #-}
 transformR f (New p) = New (MVector.transformR f =<< p)
 
@@ -93,35 +105,35 @@
 
  #-}
 
-slice :: Int -> Int -> New a -> New a
+slice :: Vector v a => Int -> Int -> New v a -> New v a
 {-# INLINE_STREAM slice #-}
 slice i n m = apply (MVector.slice i n) m
 
-init :: New a -> New a
+init :: Vector v a => New v a -> New v a
 {-# INLINE_STREAM init #-}
 init m = apply MVector.init m
 
-tail :: New a -> New a
+tail :: Vector v a => New v a -> New v a
 {-# INLINE_STREAM tail #-}
 tail m = apply MVector.tail m
 
-take :: Int -> New a -> New a
+take :: Vector v a => Int -> New v a -> New v a
 {-# INLINE_STREAM take #-}
 take n m = apply (MVector.take n) m
 
-drop :: Int -> New a -> New a
+drop :: Vector v a => Int -> New v a -> New v a
 {-# INLINE_STREAM drop #-}
 drop n m = apply (MVector.drop n) m
 
-unsafeSlice :: Int -> Int -> New a -> New a
+unsafeSlice :: Vector v a => Int -> Int -> New v a -> New v a
 {-# INLINE_STREAM unsafeSlice #-}
 unsafeSlice i n m = apply (MVector.unsafeSlice i n) m
 
-unsafeInit :: New a -> New a
+unsafeInit :: Vector v a => New v a -> New v a
 {-# INLINE_STREAM unsafeInit #-}
 unsafeInit m = apply MVector.unsafeInit m
 
-unsafeTail :: New a -> New a
+unsafeTail :: Vector v a => New v a -> New v a
 {-# INLINE_STREAM unsafeTail #-}
 unsafeTail m = apply MVector.unsafeTail m
 
@@ -152,24 +164,4 @@
   unsafeTail (unstream s) = unstream (Stream.tail s)
 
   #-}
-
-unsafeAccum :: (a -> b -> a) -> New a -> Stream (Int, b) -> New a
-{-# INLINE_STREAM unsafeAccum #-}
-unsafeAccum f m s = s `seq` modify m (\v -> MVector.unsafeAccum f v s)
-
-accum :: (a -> b -> a) -> New a -> Stream (Int, b) -> New a
-{-# INLINE_STREAM accum #-}
-accum f m s = s `seq` modify m (\v -> MVector.accum f v s)
-
-unsafeUpdate :: New a -> Stream (Int, a) -> New a
-{-# INLINE_STREAM unsafeUpdate #-}
-unsafeUpdate m s = s `seq` modify m (\v -> MVector.unsafeUpdate v s)
-
-update :: New a -> Stream (Int, a) -> New a
-{-# INLINE_STREAM update #-}
-update m s = s `seq` 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/Internal/Check.hs b/Data/Vector/Internal/Check.hs
--- a/Data/Vector/Internal/Check.hs
+++ b/Data/Vector/Internal/Check.hs
@@ -54,8 +54,8 @@
 error file line kind loc msg
   = P.error $ unlines $
       (if kind == Internal
-         then (["*** Internal error in package vector"
-               ,"*** Please submit a bug report"]++)
+         then (["*** Internal error in package vector ***"
+               ,"*** Please submit a bug report at http://trac.haskell.org/vector"]++)
          else id) $
       [ file ++ ":" ++ show line ++ " (" ++ loc ++ "): " ++ msg ]
 
diff --git a/Data/Vector/Mutable.hs b/Data/Vector/Mutable.hs
--- a/Data/Vector/Mutable.hs
+++ b/Data/Vector/Mutable.hs
@@ -1,8 +1,8 @@
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, TypeFamilies #-}
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
 
 -- |
 -- Module      : Data.Vector.Mutable
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -28,16 +28,18 @@
 import qualified Data.Vector.Generic.Mutable as G
 import           Data.Primitive.Array
 import           Control.Monad.Primitive
-import           Control.Monad.ST ( ST )
 
 import Prelude hiding ( length, read )
 
+import Data.Typeable ( Typeable )
+
 #include "vector.h"
 
 -- | Mutable boxed vectors keyed on the monad they live in ('IO' or @'ST' s@).
 data MVector s a = MVector {-# UNPACK #-} !Int
                            {-# UNPACK #-} !Int
                            {-# UNPACK #-} !(MutableArray s a)
+        deriving ( Typeable )
 
 type IOVector = MVector RealWorld
 type STVector s = MVector s
diff --git a/Data/Vector/Primitive.hs b/Data/Vector/Primitive.hs
--- a/Data/Vector/Primitive.hs
+++ b/Data/Vector/Primitive.hs
@@ -1,8 +1,8 @@
-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeFamilies #-}
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeFamilies, ScopedTypeVariables, Rank2Types #-}
 
 -- |
 -- Module      : Data.Vector.Primitive
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -19,7 +19,7 @@
   length, null,
 
   -- * Construction
-  empty, singleton, cons, snoc, replicate, generate, (++), copy,
+  empty, singleton, cons, snoc, replicate, generate, (++), force,
 
   -- * Accessing individual elements
   (!), head, last, indexM, headM, lastM,
@@ -61,7 +61,7 @@
   minIndex, minIndexBy, maxIndex, maxIndexBy,
 
   -- * Unfolding
-  unfoldr,
+  unfoldr, unfoldrN,
 
   -- * Scans
   prescanl, prescanl',
@@ -75,15 +75,25 @@
   enumFromN, enumFromStepN, enumFromTo, enumFromThenTo,
 
   -- * Conversion to/from lists
-  toList, fromList
+  toList, fromList, fromListN,
+
+  -- * Monadic operations
+  replicateM, mapM, mapM_, forM, forM_, zipWithM, zipWithM_, filterM,
+  foldM, foldM', fold1M, fold1M',
+
+  -- * Destructive operations
+  create, modify, copy, unsafeCopy
 ) where
 
 import qualified Data.Vector.Generic           as G
 import           Data.Vector.Primitive.Mutable ( MVector(..) )
+import qualified Data.Vector.Fusion.Stream as Stream
 import           Data.Primitive.ByteArray
-import           Data.Primitive ( Prim )
+import           Data.Primitive ( Prim, sizeOf )
 
 import Control.Monad ( liftM )
+import Control.Monad.ST ( ST )
+import Control.Monad.Primitive
 
 import Prelude hiding ( length, null,
                         replicate, (++),
@@ -96,18 +106,31 @@
                         foldl, foldl1, foldr, foldr1,
                         all, any, sum, product, minimum, maximum,
                         scanl, scanl1, scanr, scanr1,
-                        enumFromTo, enumFromThenTo )
+                        enumFromTo, enumFromThenTo,
+                        mapM, mapM_ )
 
 import qualified Prelude
 
+import Data.Typeable ( Typeable )
+import Data.Data     ( Data(..) )
+
 -- | Unboxed vectors of primitive types
 data Vector a = Vector {-# UNPACK #-} !Int
                        {-# UNPACK #-} !Int
                        {-# UNPACK #-} !ByteArray
+  deriving ( Typeable )
 
 instance (Show a, Prim a) => Show (Vector a) where
     show = (Prelude.++ " :: Data.Vector.Primitive.Vector") . ("fromList " Prelude.++) . show . toList
 
+instance (Data a, Prim a) => Data (Vector a) where
+  gfoldl       = G.gfoldl
+  toConstr _   = error "toConstr"
+  gunfold _ _  = error "gunfold"
+  dataTypeOf _ = G.mkType "Data.Vector.Primitive.Vector"
+  dataCast1    = G.dataCast
+
+
 type instance G.Mutable Vector = MVector
 
 instance Prim a => G.Vector Vector a where
@@ -124,17 +147,40 @@
   {-# INLINE basicUnsafeIndexM #-}
   basicUnsafeIndexM (Vector i _ arr) j = return (indexByteArray arr (i+j))
 
+  {-# INLINE basicUnsafeCopy #-}
+  basicUnsafeCopy (MVector i n dst) (Vector j _ src)
+    = memcpyByteArray' dst (i * sz) src (j * sz) (n * sz)
+    where
+      sz = sizeOf (undefined :: a)
+
   {-# INLINE elemseq #-}
   elemseq _ = seq
 
+-- See http://trac.haskell.org/vector/ticket/12
 instance (Prim a, Eq a) => Eq (Vector a) where
   {-# INLINE (==) #-}
-  (==) = G.eq
+  xs == ys = Stream.eq (G.stream xs) (G.stream ys)
 
+  {-# INLINE (/=) #-}
+  xs /= ys = not (Stream.eq (G.stream xs) (G.stream ys))
+
+-- See http://trac.haskell.org/vector/ticket/12
 instance (Prim a, Ord a) => Ord (Vector a) where
   {-# INLINE compare #-}
-  compare = G.cmp
+  compare xs ys = Stream.cmp (G.stream xs) (G.stream ys)
 
+  {-# INLINE (<) #-}
+  xs < ys = Stream.cmp (G.stream xs) (G.stream ys) == LT
+
+  {-# INLINE (<=) #-}
+  xs <= ys = Stream.cmp (G.stream xs) (G.stream ys) /= GT
+
+  {-# INLINE (>) #-}
+  xs > ys = Stream.cmp (G.stream xs) (G.stream ys) == GT
+
+  {-# INLINE (>=) #-}
+  xs >= ys = Stream.cmp (G.stream xs) (G.stream ys) /= LT
+
 -- Length
 -- ------
 
@@ -187,9 +233,9 @@
 (++) = (G.++)
 
 -- | Create a copy of a vector. Useful when dealing with slices.
-copy :: Prim a => Vector a -> Vector a
-{-# INLINE copy #-}
-copy = G.copy
+force :: Prim a => Vector a -> Vector a
+{-# INLINE force #-}
+force = G.force
 
 -- Accessing individual elements
 -- -----------------------------
@@ -657,10 +703,27 @@
 -- Unfolding
 -- ---------
 
+-- | The 'unfoldr' function is a \`dual\' to 'foldr': while 'foldr'
+-- reduces a vector to a summary value, 'unfoldr' builds a list from
+-- a seed value.  The function takes the element and returns 'Nothing'
+-- if it is done generating the vector or returns 'Just' @(a,b)@, in which
+-- case, @a@ is a prepended to the vector and @b@ is used as the next
+-- element in a recursive call.
+--
+-- A simple use of unfoldr:
+--
+-- > unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
+-- >  [10,9,8,7,6,5,4,3,2,1]
+--
 unfoldr :: Prim a => (b -> Maybe (a, b)) -> b -> Vector a
 {-# INLINE unfoldr #-}
 unfoldr = G.unfoldr
 
+-- | Unfold at most @n@ elements
+unfoldrN :: Prim a => Int -> (b -> Maybe (a, b)) -> b -> Vector a
+{-# INLINE unfoldrN #-}
+unfoldrN = G.unfoldrN
+
 -- Scans
 -- -----
 
@@ -789,4 +852,108 @@
 fromList :: Prim a => [a] -> Vector a
 {-# INLINE fromList #-}
 fromList = G.fromList
+
+-- | Convert the first @n@ elements of a list to a vector
+--
+-- > fromListN n xs = fromList (take n xs)
+fromListN :: Prim a => Int -> [a] -> Vector a
+{-# INLINE fromListN #-}
+fromListN = G.fromListN
+
+-- Monadic operations
+-- ------------------
+
+-- | Perform the monadic action the given number of times and store the
+-- results in a vector.
+replicateM :: (Monad m, Prim a) => Int -> m a -> m (Vector a)
+{-# INLINE replicateM #-}
+replicateM = G.replicateM
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+mapM :: (Monad m, Prim a, Prim b) => (a -> m b) -> Vector a -> m (Vector b)
+{-# INLINE mapM #-}
+mapM = G.mapM
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+mapM_ :: (Monad m, Prim a) => (a -> m b) -> Vector a -> m ()
+{-# INLINE mapM_ #-}
+mapM_ = G.mapM_
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+forM :: (Monad m, Prim a, Prim b) => Vector a -> (a -> m b) -> m (Vector b)
+{-# INLINE forM #-}
+forM = G.forM
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+forM_ :: (Monad m, Prim a) => Vector a -> (a -> m b) -> m ()
+{-# INLINE forM_ #-}
+forM_ = G.forM_
+
+-- | Zip the two vectors with the monadic action and yield a vector of results
+zipWithM :: (Monad m, Prim a, Prim b, Prim c)
+         => (a -> b -> m c) -> Vector a -> Vector b -> m (Vector c)
+{-# INLINE zipWithM #-}
+zipWithM = G.zipWithM
+
+-- | Zip the two vectors with the monadic action and ignore the results
+zipWithM_ :: (Monad m, Prim a, Prim b)
+          => (a -> b -> m c) -> Vector a -> Vector b -> m ()
+{-# INLINE zipWithM_ #-}
+zipWithM_ = G.zipWithM_
+
+-- | Drop elements that do not satisfy the monadic predicate
+filterM :: (Monad m, Prim a) => (a -> m Bool) -> Vector a -> m (Vector a)
+{-# INLINE filterM #-}
+filterM = G.filterM
+
+-- | Monadic fold
+foldM :: (Monad m, Prim b) => (a -> b -> m a) -> a -> Vector b -> m a
+{-# INLINE foldM #-}
+foldM = G.foldM
+
+-- | Monadic fold over non-empty vectors
+fold1M :: (Monad m, Prim a) => (a -> a -> m a) -> Vector a -> m a
+{-# INLINE fold1M #-}
+fold1M = G.fold1M
+
+-- | Monadic fold with strict accumulator
+foldM' :: (Monad m, Prim b) => (a -> b -> m a) -> a -> Vector b -> m a
+{-# INLINE foldM' #-}
+foldM' = G.foldM'
+
+-- | Monad fold over non-empty vectors with strict accumulator
+fold1M' :: (Monad m, Prim a) => (a -> a -> m a) -> Vector a -> m a
+{-# INLINE fold1M' #-}
+fold1M' = G.fold1M'
+
+-- Destructive operations
+-- ----------------------
+
+-- | Destructively initialise a vector.
+create :: Prim a => (forall s. ST s (MVector s a)) -> Vector a
+{-# INLINE create #-}
+create = G.create
+
+-- | Apply a destructive operation to a vector. The operation is applied to a
+-- copy of the vector unless it can be safely performed in place.
+modify :: Prim a => (forall s. MVector s a -> ST s ()) -> Vector a -> Vector a
+{-# INLINE modify #-}
+modify = G.modify
+
+-- | Copy an immutable vector into a mutable one. The two vectors must have
+-- the same length. This is not checked.
+unsafeCopy
+  :: (Prim a, PrimMonad m) => MVector (PrimState m) a -> Vector a -> m ()
+{-# INLINE unsafeCopy #-}
+unsafeCopy = G.unsafeCopy
+           
+-- | Copy an immutable vector into a mutable one. The two vectors must have the
+-- same length.
+copy :: (Prim a, PrimMonad m) => MVector (PrimState m) a -> Vector a -> m ()
+{-# INLINE copy #-}
+copy = G.copy
 
diff --git a/Data/Vector/Primitive/Mutable.hs b/Data/Vector/Primitive/Mutable.hs
--- a/Data/Vector/Primitive/Mutable.hs
+++ b/Data/Vector/Primitive/Mutable.hs
@@ -1,9 +1,8 @@
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, ScopedTypeVariables,
-             FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, ScopedTypeVariables #-}
 
 -- |
 -- Module      : Data.Vector.Primitive.Mutable
--- Copyright   : (c) Roman Leshchinskiy 2008-2009
+-- Copyright   : (c) Roman Leshchinskiy 2008-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -30,17 +29,19 @@
 import           Data.Primitive.ByteArray
 import           Data.Primitive ( Prim, sizeOf )
 import           Control.Monad.Primitive
-import           Control.Monad.ST ( ST )
 import           Control.Monad ( liftM )
 
 import Prelude hiding( length, read )
 
+import Data.Typeable ( Typeable )
+
 #include "vector.h"
 
 -- | Mutable vectors of primitive types.
 data MVector s a = MVector {-# UNPACK #-} !Int
                            {-# UNPACK #-} !Int
                            {-# UNPACK #-} !(MutableByteArray s)
+        deriving ( Typeable )
 
 type IOVector = MVector RealWorld
 type STVector s = MVector s
@@ -66,6 +67,12 @@
 
   {-# INLINE basicUnsafeWrite #-}
   basicUnsafeWrite (MVector i n arr) j x = writeByteArray arr (i+j) x
+
+  {-# INLINE basicUnsafeCopy #-}
+  basicUnsafeCopy (MVector i n dst) (MVector j _ src)
+    = memcpyByteArray dst (i * sz) src (j * sz) (n * sz)
+    where
+      sz = sizeOf (undefined :: a)
 
 -- | Yield a part of the mutable vector without copying it. No bounds checks
 -- are performed.
diff --git a/Data/Vector/Storable.hs b/Data/Vector/Storable.hs
--- a/Data/Vector/Storable.hs
+++ b/Data/Vector/Storable.hs
@@ -1,8 +1,8 @@
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, TypeFamilies #-}
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, TypeFamilies, Rank2Types #-}
 
 -- |
 -- Module      : Data.Vector.Storable
--- Copyright   : (c) Roman Leshchinskiy 2009-10
+-- Copyright   : (c) Roman Leshchinskiy 2009-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -19,7 +19,7 @@
   length, null,
 
   -- * Construction
-  empty, singleton, cons, snoc, replicate, generate, (++), copy,
+  empty, singleton, cons, snoc, replicate, generate, (++), force,
 
   -- * Accessing individual elements
   (!), head, last, indexM, headM, lastM,
@@ -61,7 +61,7 @@
   minIndex, minIndexBy, maxIndex, maxIndexBy,
 
   -- * Unfolding
-  unfoldr,
+  unfoldr, unfoldrN,
 
   -- * Scans
   prescanl, prescanl',
@@ -75,8 +75,15 @@
   enumFromN, enumFromStepN, enumFromTo, enumFromThenTo,
 
   -- * Conversion to/from lists
-  toList, fromList,
+  toList, fromList, fromListN,
 
+  -- * Monadic operations
+  replicateM, mapM, mapM_, forM, forM_, zipWithM, zipWithM_, filterM,
+  foldM, foldM', fold1M, fold1M',
+
+  -- * Destructive operations
+  create, modify, copy, unsafeCopy,
+
   -- * Accessing the underlying memory
   unsafeFromForeignPtr, unsafeToForeignPtr, unsafeWith
 ) where
@@ -84,13 +91,15 @@
 import qualified Data.Vector.Generic          as G
 import           Data.Vector.Storable.Mutable ( MVector(..) )
 import Data.Vector.Storable.Internal
+import qualified Data.Vector.Fusion.Stream as Stream
 
 import Foreign.Storable
 import Foreign.ForeignPtr
 import Foreign.Ptr
-import Foreign.Marshal.Array ( advancePtr )
+import Foreign.Marshal.Array ( advancePtr, copyArray )
 
-import Control.Monad.ST ( ST, runST )
+import Control.Monad.ST ( ST )
+import Control.Monad.Primitive
 
 import Prelude hiding ( length, null,
                         replicate, (++),
@@ -103,16 +112,21 @@
                         foldl, foldl1, foldr, foldr1,
                         all, any, and, or, sum, product, minimum, maximum,
                         scanl, scanl1, scanr, scanr1,
-                        enumFromTo, enumFromThenTo )
+                        enumFromTo, enumFromThenTo,
+                        mapM, mapM_ )
 
 import qualified Prelude
 
+import Data.Typeable ( Typeable )
+import Data.Data     ( Data(..) )
+
 #include "vector.h"
 
 -- | 'Storable'-based vectors
-data Vector a = Vector {-# UNPACK #-} !Int
+data Vector a = Vector {-# UNPACK #-} !(Ptr a)
                        {-# UNPACK #-} !Int
                        {-# UNPACK #-} !(ForeignPtr a)
+        deriving ( Typeable )
 
 instance (Show a, Storable a) => Show (Vector a) where
   show = (Prelude.++ " :: Data.Vector.Storable.Vector")
@@ -120,30 +134,66 @@
        . show
        . toList
 
+instance (Data a, Storable a) => Data (Vector a) where
+  gfoldl       = G.gfoldl
+  toConstr _   = error "toConstr"
+  gunfold _ _  = error "gunfold"
+  dataTypeOf _ = G.mkType "Data.Vector.Storable.Vector"
+  dataCast1    = G.dataCast
+
 type instance G.Mutable Vector = MVector
 
 instance Storable a => G.Vector Vector a where
   {-# INLINE unsafeFreeze #-}
-  unsafeFreeze (MVector i n p) = return $ Vector i n p
+  unsafeFreeze (MVector p n fp) = return $ Vector p n fp
 
   {-# INLINE basicLength #-}
   basicLength (Vector _ n _) = n
 
   {-# INLINE basicUnsafeSlice #-}
-  basicUnsafeSlice j n (Vector i _ p) = Vector (i+j) n p
+  basicUnsafeSlice i n (Vector p _ fp) = Vector (p `advancePtr` i) n fp
 
   {-# INLINE basicUnsafeIndexM #-}
-  basicUnsafeIndexM (Vector i _ p) j = return
-                                     . inlinePerformIO
-                                     $ withForeignPtr p (`peekElemOff` (i+j))
+  basicUnsafeIndexM (Vector p _ fp) i = return
+                                      . unsafeInlineIO
+                                      $ withForeignPtr fp $ \_ ->
+                                        peekElemOff p i
 
+  {-# INLINE basicUnsafeCopy #-}
+  basicUnsafeCopy (MVector p n fp) (Vector q _ fq)
+    = unsafePrimToPrim
+    $ withForeignPtr fp $ \_ ->
+      withForeignPtr fq $ \_ ->
+      copyArray p q n
+
   {-# INLINE elemseq #-}
   elemseq _ = seq
 
+-- See http://trac.haskell.org/vector/ticket/12
 instance (Storable a, Eq a) => Eq (Vector a) where
   {-# INLINE (==) #-}
-  (==) = G.eq
+  xs == ys = Stream.eq (G.stream xs) (G.stream ys)
 
+  {-# INLINE (/=) #-}
+  xs /= ys = not (Stream.eq (G.stream xs) (G.stream ys))
+
+-- See http://trac.haskell.org/vector/ticket/12
+instance (Storable a, Ord a) => Ord (Vector a) where
+  {-# INLINE compare #-}
+  compare xs ys = Stream.cmp (G.stream xs) (G.stream ys)
+
+  {-# INLINE (<) #-}
+  xs < ys = Stream.cmp (G.stream xs) (G.stream ys) == LT
+
+  {-# INLINE (<=) #-}
+  xs <= ys = Stream.cmp (G.stream xs) (G.stream ys) /= GT
+
+  {-# INLINE (>) #-}
+  xs > ys = Stream.cmp (G.stream xs) (G.stream ys) == GT
+
+  {-# INLINE (>=) #-}
+  xs >= ys = Stream.cmp (G.stream xs) (G.stream ys) /= LT
+
 {-
 eq_memcmp :: forall a. Storable a => Vector a -> Vector a -> Bool
 {-# INLINE_STREAM eq_memcmp #-}
@@ -165,9 +215,6 @@
  #-}
 -}
 
-instance (Storable a, Ord a) => Ord (Vector a) where
-  {-# INLINE compare #-}
-  compare = G.cmp
 
 -- Length
 -- ------
@@ -221,9 +268,9 @@
 (++) = (G.++)
 
 -- | Create a copy of a vector. Useful when dealing with slices.
-copy :: Storable a => Vector a -> Vector a
-{-# INLINE copy #-}
-copy = G.copy
+force :: Storable a => Vector a -> Vector a
+{-# INLINE force #-}
+force = G.force
 
 -- Accessing individual elements
 -- -----------------------------
@@ -704,10 +751,27 @@
 -- Unfolding
 -- ---------
 
+-- | The 'unfoldr' function is a \`dual\' to 'foldr': while 'foldr'
+-- reduces a vector to a summary value, 'unfoldr' builds a list from
+-- a seed value.  The function takes the element and returns 'Nothing'
+-- if it is done generating the vector or returns 'Just' @(a,b)@, in which
+-- case, @a@ is a prepended to the vector and @b@ is used as the next
+-- element in a recursive call.
+--
+-- A simple use of unfoldr:
+--
+-- > unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
+-- >  [10,9,8,7,6,5,4,3,2,1]
+--
 unfoldr :: Storable a => (b -> Maybe (a, b)) -> b -> Vector a
 {-# INLINE unfoldr #-}
 unfoldr = G.unfoldr
 
+-- | Unfold at most @n@ elements
+unfoldrN :: Storable a => Int -> (b -> Maybe (a, b)) -> b -> Vector a
+{-# INLINE unfoldrN #-}
+unfoldrN = G.unfoldrN
+
 -- Scans
 -- -----
 
@@ -841,28 +905,134 @@
 {-# INLINE fromList #-}
 fromList = G.fromList
 
+-- | Convert the first @n@ elements of a list to a vector
+--
+-- > fromListN n xs = fromList (take n xs)
+fromListN :: Storable a => Int -> [a] -> Vector a
+{-# INLINE fromListN #-}
+fromListN = G.fromListN
+
+-- Monadic operations
+-- ------------------
+
+-- | Perform the monadic action the given number of times and store the
+-- results in a vector.
+replicateM :: (Monad m, Storable a) => Int -> m a -> m (Vector a)
+{-# INLINE replicateM #-}
+replicateM = G.replicateM
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+mapM :: (Monad m, Storable a, Storable b) => (a -> m b) -> Vector a -> m (Vector b)
+{-# INLINE mapM #-}
+mapM = G.mapM
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+mapM_ :: (Monad m, Storable a) => (a -> m b) -> Vector a -> m ()
+{-# INLINE mapM_ #-}
+mapM_ = G.mapM_
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+forM :: (Monad m, Storable a, Storable b) => Vector a -> (a -> m b) -> m (Vector b)
+{-# INLINE forM #-}
+forM = G.forM
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+forM_ :: (Monad m, Storable a) => Vector a -> (a -> m b) -> m ()
+{-# INLINE forM_ #-}
+forM_ = G.forM_
+
+-- | Zip the two vectors with the monadic action and yield a vector of results
+zipWithM :: (Monad m, Storable a, Storable b, Storable c)
+         => (a -> b -> m c) -> Vector a -> Vector b -> m (Vector c)
+{-# INLINE zipWithM #-}
+zipWithM = G.zipWithM
+
+-- | Zip the two vectors with the monadic action and ignore the results
+zipWithM_ :: (Monad m, Storable a, Storable b)
+          => (a -> b -> m c) -> Vector a -> Vector b -> m ()
+{-# INLINE zipWithM_ #-}
+zipWithM_ = G.zipWithM_
+
+-- | Drop elements that do not satisfy the monadic predicate
+filterM :: (Monad m, Storable a) => (a -> m Bool) -> Vector a -> m (Vector a)
+{-# INLINE filterM #-}
+filterM = G.filterM
+
+-- | Monadic fold
+foldM :: (Monad m, Storable b) => (a -> b -> m a) -> a -> Vector b -> m a
+{-# INLINE foldM #-}
+foldM = G.foldM
+
+-- | Monadic fold over non-empty vectors
+fold1M :: (Monad m, Storable a) => (a -> a -> m a) -> Vector a -> m a
+{-# INLINE fold1M #-}
+fold1M = G.fold1M
+
+-- | Monadic fold with strict accumulator
+foldM' :: (Monad m, Storable b) => (a -> b -> m a) -> a -> Vector b -> m a
+{-# INLINE foldM' #-}
+foldM' = G.foldM'
+
+-- | Monad fold over non-empty vectors with strict accumulator
+fold1M' :: (Monad m, Storable a) => (a -> a -> m a) -> Vector a -> m a
+{-# INLINE fold1M' #-}
+fold1M' = G.fold1M'
+
+-- Destructive operations
+-- ----------------------
+
+-- | Destructively initialise a vector.
+create :: Storable a => (forall s. ST s (MVector s a)) -> Vector a
+{-# INLINE create #-}
+create = G.create
+
+-- | Apply a destructive operation to a vector. The operation is applied to a
+-- copy of the vector unless it can be safely performed in place.
+modify
+  :: Storable a => (forall s. MVector s a -> ST s ()) -> Vector a -> Vector a
+{-# INLINE modify #-}
+modify = G.modify
+
+-- | Copy an immutable vector into a mutable one. The two vectors must have
+-- the same length. This is not checked.
+unsafeCopy
+  :: (Storable a, PrimMonad m) => MVector (PrimState m) a -> Vector a -> m ()
+{-# INLINE unsafeCopy #-}
+unsafeCopy = G.unsafeCopy
+           
+-- | Copy an immutable vector into a mutable one. The two vectors must have the
+-- same length.
+copy :: (Storable a, PrimMonad m) => MVector (PrimState m) a -> Vector a -> m ()
+{-# INLINE copy #-}
+copy = G.copy
+
 -- Accessing the underlying memory
 -- -------------------------------
 
 -- | Create a vector from a 'ForeignPtr' with an offset and a length. The data
 -- may not be modified through the 'ForeignPtr' afterwards.
-unsafeFromForeignPtr :: ForeignPtr a    -- ^ pointer
+unsafeFromForeignPtr :: Storable a
+                     => ForeignPtr a    -- ^ pointer
                      -> Int             -- ^ offset
                      -> Int             -- ^ length
                      -> Vector a
 {-# INLINE unsafeFromForeignPtr #-}
-unsafeFromForeignPtr p i n = Vector i n p
+unsafeFromForeignPtr fp i n = Vector (offsetToPtr fp i) n fp
 
 -- | Yield the underlying 'ForeignPtr' together with the offset to the data
 -- and its length. The data may not be modified through the 'ForeignPtr'.
-unsafeToForeignPtr :: Vector a -> (ForeignPtr a, Int, Int)
+unsafeToForeignPtr :: Storable a => Vector a -> (ForeignPtr a, Int, Int)
 {-# INLINE unsafeToForeignPtr #-}
-unsafeToForeignPtr (Vector i n p) = (p,i,n)
+unsafeToForeignPtr (Vector p n fp) = (fp, ptrToOffset fp p, n)
 
 -- | Pass a pointer to the vector's data to the IO action. The data may not be
 -- modified through the 'Ptr.
 unsafeWith :: Storable a => Vector a -> (Ptr a -> IO b) -> IO b
 {-# INLINE unsafeWith #-}
-unsafeWith (Vector i n fp) m
-  = withForeignPtr fp $ \p -> m (p `advancePtr` i)
+unsafeWith (Vector p n fp) m = withForeignPtr fp $ \_ -> m p
+
 
diff --git a/Data/Vector/Storable/Internal.hs b/Data/Vector/Storable/Internal.hs
--- a/Data/Vector/Storable/Internal.hs
+++ b/Data/Vector/Storable/Internal.hs
@@ -1,8 +1,8 @@
-{-# LANGUAGE MagicHash, UnboxedTuples #-}
+{-# LANGUAGE MagicHash, UnboxedTuples, ScopedTypeVariables #-}
 
 -- |
 -- Module      : Data.Vector.Storable.Internal
--- Copyright   : (c) Roman Leshchinskiy 2009
+-- Copyright   : (c) Roman Leshchinskiy 2009-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -12,14 +12,28 @@
 -- Ugly internal utility functions for implementing 'Storable'-based vectors.
 --
 
-module Data.Vector.Storable.Internal
-where
+module Data.Vector.Storable.Internal (
+  ptrToOffset, offsetToPtr
+) where
 
-import GHC.Base         ( realWorld# )
-import GHC.IOBase       ( IO(..) )
+import Control.Monad.Primitive ( unsafeInlineIO )
+import Foreign.Storable
+import Foreign.ForeignPtr
+import Foreign.Ptr
+import Foreign.Marshal.Array ( advancePtr )
+import GHC.Base         ( quotInt )
 
--- Stolen from the ByteString library
-inlinePerformIO :: IO a -> a
-{-# INLINE inlinePerformIO #-}
-inlinePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
+distance :: forall a. Storable a => Ptr a -> Ptr a -> Int
+{-# INLINE distance #-}
+distance p q = (p `minusPtr` q) `quotInt` sizeOf (undefined :: a)
+
+ptrToOffset :: Storable a => ForeignPtr a -> Ptr a -> Int
+{-# INLINE ptrToOffset #-}
+ptrToOffset fp q = unsafeInlineIO
+                 $ withForeignPtr fp $ \p -> return (distance p q)
+
+offsetToPtr :: Storable a => ForeignPtr a -> Int -> Ptr a
+{-# INLINE offsetToPtr #-}
+offsetToPtr fp i = unsafeInlineIO
+                 $ withForeignPtr fp $ \p -> return (advancePtr p i)
 
diff --git a/Data/Vector/Storable/Mutable.hs b/Data/Vector/Storable/Mutable.hs
--- a/Data/Vector/Storable/Mutable.hs
+++ b/Data/Vector/Storable/Mutable.hs
@@ -29,22 +29,27 @@
 ) where
 
 import qualified Data.Vector.Generic.Mutable as G
+import Data.Vector.Storable.Internal
 
 import Foreign.Storable
 import Foreign.ForeignPtr
 import Foreign.Ptr
-import Foreign.Marshal.Array ( advancePtr )
+import Foreign.Marshal.Array ( advancePtr, copyArray )
+import Foreign.C.Types ( CInt )
 
 import Control.Monad.Primitive
 
 import Prelude hiding( length, read )
 
+import Data.Typeable ( Typeable )
+
 #include "vector.h"
 
 -- | Mutable 'Storable'-based vectors
-data MVector s a = MVector {-# UNPACK #-} !Int
+data MVector s a = MVector {-# UNPACK #-} !(Ptr a)
                            {-# UNPACK #-} !Int
                            {-# UNPACK #-} !(ForeignPtr a)
+        deriving ( Typeable )
 
 type IOVector = MVector RealWorld
 type STVector s = MVector s
@@ -54,51 +59,63 @@
   basicLength (MVector _ n _) = n
 
   {-# INLINE basicUnsafeSlice #-}
-  basicUnsafeSlice j m (MVector i n p) = MVector (i+j) m p
+  basicUnsafeSlice j m (MVector p n fp) = MVector (p `advancePtr` j) m fp
 
-  -- FIXME: implement this properly
+  -- FIXME: this relies on non-portable pointer comparisons
   {-# INLINE basicOverlaps #-}
-  basicOverlaps (MVector i m p) (MVector j n q) = True
+  basicOverlaps (MVector p m _) (MVector q n _)
+    = between p q (q `advancePtr` n) || between q p (p `advancePtr` m)
+    where
+      between x y z = x >= y && x < z
 
   {-# INLINE basicUnsafeNew #-}
   basicUnsafeNew n
     = unsafePrimToPrim
-    $ MVector 0 n `fmap` mallocForeignPtrArray n
+    $ do
+        fp <- mallocForeignPtrArray n
+        withForeignPtr fp $ \p -> return $ MVector p n fp
 
   {-# INLINE basicUnsafeRead #-}
-  basicUnsafeRead (MVector i n p) j
+  basicUnsafeRead (MVector p _ fp) i
     = unsafePrimToPrim
-    $ withForeignPtr p $ \ptr -> peekElemOff ptr (i+j)
+    $ withForeignPtr fp $ \_ -> peekElemOff p i
 
   {-# INLINE basicUnsafeWrite #-}
-  basicUnsafeWrite (MVector i n p) j x
+  basicUnsafeWrite (MVector p n fp) i x
     = unsafePrimToPrim
-    $ withForeignPtr p $ \ptr -> pokeElemOff ptr (i+j) x
+    $ withForeignPtr fp $ \_ -> pokeElemOff p i x
 
+  {-# INLINE basicUnsafeCopy #-}
+  basicUnsafeCopy (MVector p n fp) (MVector q _ fq)
+    = unsafePrimToPrim
+    $ withForeignPtr fp $ \_ ->
+      withForeignPtr fq $ \_ ->
+      copyArray p q n
+
 -- | Create a mutable vector from a 'ForeignPtr' with an offset and a length.
 -- Modifying data through the 'ForeignPtr' afterwards is unsafe if the vector
 -- could have been frozen before the modification.
-unsafeFromForeignPtr :: ForeignPtr a    -- ^ pointer
+unsafeFromForeignPtr :: Storable a
+                     => ForeignPtr a    -- ^ pointer
                      -> Int             -- ^ offset
                      -> Int             -- ^ length
                      -> MVector s a
 {-# INLINE unsafeFromForeignPtr #-}
-unsafeFromForeignPtr p i n = MVector i n p
+unsafeFromForeignPtr fp i n = MVector (offsetToPtr fp i) n fp
 
 -- | Yield the underlying 'ForeignPtr' together with the offset to the data
 -- and its length. Modifying the data through the 'ForeignPtr' is
 -- unsafe if the vector could have frozen before the modification.
-unsafeToForeignPtr :: MVector s a -> (ForeignPtr a, Int, Int)
+unsafeToForeignPtr :: Storable a => MVector s a -> (ForeignPtr a, Int, Int)
 {-# INLINE unsafeToForeignPtr #-}
-unsafeToForeignPtr (MVector i n p) = (p,i,n)
+unsafeToForeignPtr (MVector p n fp) = (fp, ptrToOffset fp p, n)
 
 -- | Pass a pointer to the vector's data to the IO action. Modifying data
 -- through the pointer is unsafe if the vector could have been frozen before
 -- the modification.
 unsafeWith :: Storable a => IOVector a -> (Ptr a -> IO b) -> IO b
 {-# INLINE unsafeWith #-}
-unsafeWith (MVector i n fp) m
-  = withForeignPtr fp $ \p -> m (p `advancePtr` i)
+unsafeWith (MVector p n fp) m = withForeignPtr fp $ \_ -> m p
 
 -- | Yield a part of the mutable vector without copying it. No bounds checks
 -- are performed.
diff --git a/Data/Vector/Unboxed.hs b/Data/Vector/Unboxed.hs
--- a/Data/Vector/Unboxed.hs
+++ b/Data/Vector/Unboxed.hs
@@ -1,6 +1,8 @@
+{-# LANGUAGE Rank2Types #-}
+
 -- |
 -- Module      : Data.Vector.Unboxed
--- Copyright   : (c) Roman Leshchinskiy 2009
+-- Copyright   : (c) Roman Leshchinskiy 2009-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -17,7 +19,7 @@
   length, null,
 
   -- * Construction
-  empty, singleton, cons, snoc, replicate, generate, (++), copy,
+  empty, singleton, cons, snoc, replicate, generate, (++), force,
 
   -- * Accessing individual elements
   (!), head, last, indexM, headM, lastM,
@@ -63,7 +65,7 @@
   minIndex, minIndexBy, maxIndex, maxIndexBy,
 
   -- * Unfolding
-  unfoldr,
+  unfoldr, unfoldrN,
 
   -- * Scans
   prescanl, prescanl',
@@ -77,13 +79,23 @@
   enumFromN, enumFromStepN, enumFromTo, enumFromThenTo,
 
   -- * Conversion to/from lists
-  toList, fromList
+  toList, fromList, fromListN,
+
+  -- * Monadic operations
+  replicateM, mapM, mapM_, forM, forM_, zipWithM, zipWithM_, filterM,
+  foldM, foldM', fold1M, fold1M',
+
+  -- * Destructive operations
+  create, modify, copy, unsafeCopy
 ) where
 
 import Data.Vector.Unboxed.Base
 import qualified Data.Vector.Generic as G
 import qualified Data.Vector.Fusion.Stream as Stream
 
+import Control.Monad.ST ( ST )
+import Control.Monad.Primitive
+
 import Prelude hiding ( length, null,
                         replicate, (++),
                         head, last,
@@ -95,19 +107,37 @@
                         foldl, foldl1, foldr, foldr1,
                         all, any, and, or, sum, product, minimum, maximum,
                         scanl, scanl1, scanr, scanr1,
-                        enumFromTo, enumFromThenTo )
+                        enumFromTo, enumFromThenTo,
+                        mapM, mapM_ )
 import qualified Prelude
 
 #include "vector.h"
 
+-- See http://trac.haskell.org/vector/ticket/12
 instance (Unbox a, Eq a) => Eq (Vector a) where
   {-# INLINE (==) #-}
-  (==) = G.eq
+  xs == ys = Stream.eq (G.stream xs) (G.stream ys)
 
+  {-# INLINE (/=) #-}
+  xs /= ys = not (Stream.eq (G.stream xs) (G.stream ys))
+
+-- See http://trac.haskell.org/vector/ticket/12
 instance (Unbox a, Ord a) => Ord (Vector a) where
   {-# INLINE compare #-}
-  compare = G.cmp
+  compare xs ys = Stream.cmp (G.stream xs) (G.stream ys)
 
+  {-# INLINE (<) #-}
+  xs < ys = Stream.cmp (G.stream xs) (G.stream ys) == LT
+
+  {-# INLINE (<=) #-}
+  xs <= ys = Stream.cmp (G.stream xs) (G.stream ys) /= GT
+
+  {-# INLINE (>) #-}
+  xs > ys = Stream.cmp (G.stream xs) (G.stream ys) == GT
+
+  {-# INLINE (>=) #-}
+  xs >= ys = Stream.cmp (G.stream xs) (G.stream ys) /= LT
+
 instance (Show a, Unbox a) => Show (Vector a) where
     show = (Prelude.++ " :: Data.Vector.Unboxed.Vector") . ("fromList " Prelude.++) . show . toList
 
@@ -163,9 +193,9 @@
 (++) = (G.++)
 
 -- | Create a copy of a vector. Useful when dealing with slices.
-copy :: Unbox a => Vector a -> Vector a
-{-# INLINE copy #-}
-copy = G.copy
+force :: Unbox a => Vector a -> Vector a
+{-# INLINE force #-}
+force = G.force
 
 -- Accessing individual elements
 -- -----------------------------
@@ -659,10 +689,27 @@
 -- Unfolding
 -- ---------
 
+-- | The 'unfoldr' function is a \`dual\' to 'foldr': while 'foldr'
+-- reduces a vector to a summary value, 'unfoldr' builds a list from
+-- a seed value.  The function takes the element and returns 'Nothing'
+-- if it is done generating the vector or returns 'Just' @(a,b)@, in which
+-- case, @a@ is a prepended to the vector and @b@ is used as the next
+-- element in a recursive call.
+--
+-- A simple use of unfoldr:
+--
+-- > unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
+-- >  [10,9,8,7,6,5,4,3,2,1]
+--
 unfoldr :: Unbox a => (b -> Maybe (a, b)) -> b -> Vector a
 {-# INLINE unfoldr #-}
 unfoldr = G.unfoldr
 
+-- | Unfold at most @n@ elements
+unfoldrN :: Unbox a => Int -> (b -> Maybe (a, b)) -> b -> Vector a
+{-# INLINE unfoldrN #-}
+unfoldrN = G.unfoldrN
+
 -- Scans
 -- -----
 
@@ -791,6 +838,111 @@
 fromList :: Unbox a => [a] -> Vector a
 {-# INLINE fromList #-}
 fromList = G.fromList
+
+-- | Convert the first @n@ elements of a list to a vector
+--
+-- > fromListN n xs = fromList (take n xs)
+fromListN :: Unbox a => Int -> [a] -> Vector a
+{-# INLINE fromListN #-}
+fromListN = G.fromListN
+
+-- Monadic operations
+-- ------------------
+
+-- | Perform the monadic action the given number of times and store the
+-- results in a vector.
+replicateM :: (Monad m, Unbox a) => Int -> m a -> m (Vector a)
+{-# INLINE replicateM #-}
+replicateM = G.replicateM
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+mapM :: (Monad m, Unbox a, Unbox b) => (a -> m b) -> Vector a -> m (Vector b)
+{-# INLINE mapM #-}
+mapM = G.mapM
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+mapM_ :: (Monad m, Unbox a) => (a -> m b) -> Vector a -> m ()
+{-# INLINE mapM_ #-}
+mapM_ = G.mapM_
+
+-- | Apply the monadic action to all elements of the vector, yielding a vector
+-- of results
+forM :: (Monad m, Unbox a, Unbox b) => Vector a -> (a -> m b) -> m (Vector b)
+{-# INLINE forM #-}
+forM = G.forM
+
+-- | Apply the monadic action to all elements of a vector and ignore the
+-- results
+forM_ :: (Monad m, Unbox a) => Vector a -> (a -> m b) -> m ()
+{-# INLINE forM_ #-}
+forM_ = G.forM_
+
+-- | Zip the two vectors with the monadic action and yield a vector of results
+zipWithM :: (Monad m, Unbox a, Unbox b, Unbox c)
+         => (a -> b -> m c) -> Vector a -> Vector b -> m (Vector c)
+{-# INLINE zipWithM #-}
+zipWithM = G.zipWithM
+
+-- | Zip the two vectors with the monadic action and ignore the results
+zipWithM_ :: (Monad m, Unbox a, Unbox b)
+          => (a -> b -> m c) -> Vector a -> Vector b -> m ()
+{-# INLINE zipWithM_ #-}
+zipWithM_ = G.zipWithM_
+
+-- | Drop elements that do not satisfy the monadic predicate
+filterM :: (Monad m, Unbox a) => (a -> m Bool) -> Vector a -> m (Vector a)
+{-# INLINE filterM #-}
+filterM = G.filterM
+
+-- | Monadic fold
+foldM :: (Monad m, Unbox b) => (a -> b -> m a) -> a -> Vector b -> m a
+{-# INLINE foldM #-}
+foldM = G.foldM
+
+-- | Monadic fold over non-empty vectors
+fold1M :: (Monad m, Unbox a) => (a -> a -> m a) -> Vector a -> m a
+{-# INLINE fold1M #-}
+fold1M = G.fold1M
+
+-- | Monadic fold with strict accumulator
+foldM' :: (Monad m, Unbox b) => (a -> b -> m a) -> a -> Vector b -> m a
+{-# INLINE foldM' #-}
+foldM' = G.foldM'
+
+-- | Monad fold over non-empty vectors with strict accumulator
+fold1M' :: (Monad m, Unbox a) => (a -> a -> m a) -> Vector a -> m a
+{-# INLINE fold1M' #-}
+fold1M' = G.fold1M'
+
+-- Destructive operations
+-- ----------------------
+
+-- | Destructively initialise a vector.
+create :: Unbox a => (forall s. ST s (MVector s a)) -> Vector a
+{-# INLINE create #-}
+create = G.create
+
+-- | Apply a destructive operation to a vector. The operation is applied to a
+-- copy of the vector unless it can be safely performed in place.
+modify :: Unbox a => (forall s. MVector s a -> ST s ()) -> Vector a -> Vector a
+{-# INLINE modify #-}
+modify = G.modify
+
+-- | Copy an immutable vector into a mutable one. The two vectors must have
+-- the same length. This is not checked.
+unsafeCopy
+  :: (Unbox a, PrimMonad m) => MVector (PrimState m) a -> Vector a -> m ()
+{-# INLINE unsafeCopy #-}
+unsafeCopy = G.unsafeCopy
+           
+-- | Copy an immutable vector into a mutable one. The two vectors must have the
+-- same length.
+copy :: (Unbox a, PrimMonad m) => MVector (PrimState m) a -> Vector a -> m ()
+{-# INLINE copy #-}
+copy = G.copy
+
 
 #define DEFINE_IMMUTABLE
 #include "unbox-tuple-instances"
diff --git a/Data/Vector/Unboxed/Base.hs b/Data/Vector/Unboxed/Base.hs
--- a/Data/Vector/Unboxed/Base.hs
+++ b/Data/Vector/Unboxed/Base.hs
@@ -1,8 +1,7 @@
-{-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleContexts,
-             ScopedTypeVariables #-}
+{-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleContexts #-}
 -- |
 -- Module      : Data.Vector.Unboxed.Base
--- Copyright   : (c) Roman Leshchinskiy 2009
+-- Copyright   : (c) Roman Leshchinskiy 2009-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
@@ -22,13 +21,15 @@
 import qualified Data.Vector.Primitive as P
 
 import Control.Monad.Primitive
-import Control.Monad.ST ( runST )
 import Control.Monad ( liftM )
 
 import Data.Word ( Word, Word8, Word16, Word32, Word64 )
 import Data.Int  ( Int8, Int16, Int32, Int64 )
 import Data.Complex
 
+import Data.Typeable ( Typeable1(..), Typeable2(..), mkTyConApp, mkTyCon )
+import Data.Data     ( Data(..) )
+
 #include "vector.h"
 
 data family MVector s a
@@ -41,7 +42,26 @@
 
 class (G.Vector Vector a, M.MVector MVector a) => Unbox a
 
+-- -----------------
+-- Data and Typeable
+-- -----------------
 
+vectorTy :: String
+vectorTy = "Data.Vector.Unboxed.Vector"
+
+instance Typeable1 Vector where
+  typeOf1 _ = mkTyConApp (mkTyCon vectorTy) []
+
+instance Typeable2 MVector where
+  typeOf2 _ = mkTyConApp (mkTyCon "Data.Vector.Unboxed.Mutable.MVector") []
+
+instance (Data a, Unbox a) => Data (Vector a) where
+  gfoldl       = G.gfoldl
+  toConstr _   = error "toConstr"
+  gunfold _ _  = error "gunfold"
+  dataTypeOf _ = G.mkType vectorTy
+  dataCast1    = G.dataCast
+
 -- ----
 -- Unit
 -- ----
@@ -96,6 +116,9 @@
   {-# INLINE basicUnsafeIndexM #-}
   basicUnsafeIndexM (V_Unit _) i = return ()
 
+  {-# INLINE basicUnsafeCopy #-}
+  basicUnsafeCopy (MV_Unit _) (V_Unit _) = return ()
+
   {-# INLINE elemseq #-}
   elemseq _ = seq
 
@@ -140,6 +163,7 @@
 ; basicLength (con v) = G.basicLength v                                 \
 ; basicUnsafeSlice i n (con v) = con $ G.basicUnsafeSlice i n v         \
 ; basicUnsafeIndexM (con v) i = G.basicUnsafeIndexM v i                 \
+; basicUnsafeCopy (mcon mv) (con v) = G.basicUnsafeCopy mv v            \
 ; elemseq _ = seq }
 
 newtype instance MVector s Int = MV_Int (P.MVector s Int)
@@ -276,6 +300,7 @@
   basicLength (V_Bool v) = G.basicLength v
   basicUnsafeSlice i n (V_Bool v) = V_Bool $ G.basicUnsafeSlice i n v
   basicUnsafeIndexM (V_Bool v) i = toBool `liftM` G.basicUnsafeIndexM v i
+  basicUnsafeCopy (MV_Bool mv) (V_Bool v) = G.basicUnsafeCopy mv v
   elemseq _ = seq
 
 -- -------
@@ -322,6 +347,8 @@
   basicUnsafeSlice i n (V_Complex v) = V_Complex $ G.basicUnsafeSlice i n v
   basicUnsafeIndexM (V_Complex v) i
                 = uncurry (:+) `liftM` G.basicUnsafeIndexM v i
+  basicUnsafeCopy (MV_Complex mv) (V_Complex v)
+                = G.basicUnsafeCopy mv v
   elemseq _ (x :+ y) z = G.elemseq (undefined :: Vector a) x
                        $ G.elemseq (undefined :: Vector a) y z
 
diff --git a/Data/Vector/Unboxed/Mutable.hs b/Data/Vector/Unboxed/Mutable.hs
--- a/Data/Vector/Unboxed/Mutable.hs
+++ b/Data/Vector/Unboxed/Mutable.hs
@@ -1,6 +1,6 @@
 -- |
 -- Module      : Data.Vector.Unboxed.Mutable
--- Copyright   : (c) Roman Leshchinskiy 2009
+-- Copyright   : (c) Roman Leshchinskiy 2009-2010
 -- License     : BSD-style
 --
 -- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
diff --git a/benchmarks/Algo/AwShCC.hs b/benchmarks/Algo/AwShCC.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Algo/AwShCC.hs
@@ -0,0 +1,38 @@
+{-# OPTIONS -fno-spec-constr-count #-}
+module Algo.AwShCC (awshcc) where
+
+import Data.Vector.Unboxed as V
+
+awshcc :: (Int, Vector Int, Vector Int) -> Vector Int
+{-# NOINLINE awshcc #-}
+awshcc (n, es1, es2) = concomp ds es1' es2'
+    where
+      ds = V.enumFromTo 0 (n-1) V.++ V.enumFromTo 0 (n-1)
+      es1' = es1 V.++ es2
+      es2' = es2 V.++ es1
+
+      starCheck ds = V.backpermute st' gs
+        where
+          gs  = V.backpermute ds ds
+          st  = V.zipWith (==) ds gs
+          st' = V.update st . V.filter (not . snd)
+                            $ V.zip gs st
+
+      concomp ds es1 es2
+        | V.and (starCheck ds'') = ds''
+        | otherwise              = concomp (V.backpermute ds'' ds'') es1 es2
+        where
+          ds'  = V.update ds
+               . V.map (\(di, dj, gi) -> (di, dj))
+               . V.filter (\(di, dj, gi) -> gi == di && di > dj)
+               $ V.zip3 (V.backpermute ds es1)
+                        (V.backpermute ds es2)
+                        (V.backpermute ds (V.backpermute ds es1))
+
+          ds'' = V.update ds'
+               . V.map (\(di, dj, st) -> (di, dj))
+               . V.filter (\(di, dj, st) -> st && di /= dj)
+               $ V.zip3 (V.backpermute ds' es1)
+                        (V.backpermute ds' es2)
+                        (V.backpermute (starCheck ds') es1)
+
diff --git a/benchmarks/Algo/HybCC.hs b/benchmarks/Algo/HybCC.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Algo/HybCC.hs
@@ -0,0 +1,42 @@
+module Algo.HybCC (hybcc) where
+
+import Data.Vector.Unboxed as V
+
+hybcc :: (Int, Vector Int, Vector Int) -> Vector Int
+{-# NOINLINE hybcc #-}
+hybcc (n, e1, e2) = concomp (V.zip e1 e2) n
+    where
+      concomp es n
+        | V.null es = V.enumFromTo 0 (n-1)
+        | otherwise = V.backpermute ins ins
+        where
+          p = shortcut_all
+            $ V.update (V.enumFromTo 0 (n-1)) es
+
+          (es',i) = compress p es
+          r = concomp es' (V.length i)
+          ins = V.update_ p i
+              $ V.backpermute i r
+
+      enumerate bs = V.prescanl' (+) 0 $ V.map (\b -> if b then 1 else 0) bs
+
+      pack_index bs = V.map fst
+                    . V.filter snd
+                    $ V.zip (V.enumFromTo 0 (V.length bs - 1)) bs
+
+      shortcut_all p | p == pp   = pp
+                     | otherwise = shortcut_all pp
+        where
+          pp = V.backpermute p p
+
+      compress p es = (new_es, pack_index roots)
+        where
+          (e1,e2) = V.unzip es
+          es' = V.map (\(x,y) -> if x > y then (y,x) else (x,y))
+              . V.filter (\(x,y) -> x /= y)
+              $ V.zip (V.backpermute p e1) (V.backpermute p e2)
+
+          roots = V.zipWith (==) p (V.enumFromTo 0 (V.length p - 1))
+          labels = enumerate roots
+          (e1',e2') = V.unzip es'
+          new_es = V.zip (V.backpermute labels e1') (V.backpermute labels e2')
diff --git a/benchmarks/Algo/Leaffix.hs b/benchmarks/Algo/Leaffix.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Algo/Leaffix.hs
@@ -0,0 +1,16 @@
+module Algo.Leaffix where
+
+import Data.Vector.Unboxed as V
+
+leaffix :: (Vector Int, Vector Int) -> Vector Int
+{-# NOINLINE leaffix #-}
+leaffix (ls,rs)
+    = leaffix (V.replicate (V.length ls) 1) ls rs
+    where
+      leaffix xs ls rs
+        = let zs   = V.replicate (V.length ls * 2) 0
+              vs   = V.update_ zs ls xs
+              sums = V.prescanl' (+) 0 vs
+          in
+          V.zipWith (-) (V.backpermute sums ls) (V.backpermute sums rs)
+
diff --git a/benchmarks/Algo/ListRank.hs b/benchmarks/Algo/ListRank.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Algo/ListRank.hs
@@ -0,0 +1,21 @@
+module Algo.ListRank
+where
+
+import Data.Vector.Unboxed as V
+
+listRank :: Int -> Vector Int
+{-# NOINLINE listRank #-}
+listRank n = pointer_jump xs val
+  where
+    xs = 0 `V.cons` V.enumFromTo 0 (n-2)
+
+    val = V.zipWith (\i j -> if i == j then 0 else 1)
+                    xs (V.enumFromTo 0 (n-1))
+
+    pointer_jump pt val
+      | npt == pt = val
+      | otherwise = pointer_jump npt nval
+      where
+        npt  = V.backpermute pt pt
+        nval = V.zipWith (+) val (V.backpermute val pt)
+
diff --git a/benchmarks/Algo/Quickhull.hs b/benchmarks/Algo/Quickhull.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Algo/Quickhull.hs
@@ -0,0 +1,32 @@
+module Algo.Quickhull (quickhull) where
+
+import Data.Vector.Unboxed as V
+
+quickhull :: (Vector Double, Vector Double) -> (Vector Double, Vector Double)
+{-# NOINLINE quickhull #-}
+quickhull (xs, ys) = xs' `seq` ys' `seq` (xs',ys')
+    where
+      (xs',ys') = V.unzip
+                $ hsplit points pmin pmax V.++ hsplit points pmax pmin
+
+      imin = V.minIndex xs
+      imax = V.maxIndex xs
+
+      points = V.zip xs ys
+      pmin   = points V.! imin
+      pmax   = points V.! imax
+
+
+      hsplit points p1 p2
+        | V.length packed < 2 = p1 `V.cons` packed
+        | otherwise = hsplit packed p1 pm V.++ hsplit packed pm p2
+        where
+          cs     = V.map (\p -> cross p p1 p2) points
+          packed = V.map fst
+                 $ V.filter (\t -> snd t > 0)
+                 $ V.zip points cs
+
+          pm     = points V.! V.maxIndex cs
+
+      cross (x,y) (x1,y1) (x2,y2) = (x1-x)*(y2-y) - (y1-y)*(x2-x)
+
diff --git a/benchmarks/Algo/Rootfix.hs b/benchmarks/Algo/Rootfix.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Algo/Rootfix.hs
@@ -0,0 +1,15 @@
+module Algo.Rootfix where
+
+import Data.Vector.Unboxed as V
+
+rootfix :: (V.Vector Int, V.Vector Int) -> V.Vector Int
+{-# NOINLINE rootfix #-}
+rootfix (ls, rs) = rootfix (V.replicate (V.length ls) 1) ls rs
+    where
+      rootfix xs ls rs
+        = let zs   = V.replicate (V.length ls * 2) 0
+              vs   = V.update_ (V.update_ zs ls xs) rs (V.map negate xs)
+              sums = V.prescanl' (+) 0 vs
+          in
+          V.backpermute sums ls
+
diff --git a/benchmarks/Algo/Spectral.hs b/benchmarks/Algo/Spectral.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Algo/Spectral.hs
@@ -0,0 +1,21 @@
+module Algo.Spectral ( spectral ) where
+
+import Data.Vector.Unboxed as V
+
+import Data.Bits
+
+spectral :: Vector Double -> Vector Double
+{-# NOINLINE spectral #-}
+spectral us = us `seq` V.map row (V.enumFromTo 0 (n-1))
+    where
+      n = V.length us
+
+      row i = i `seq` V.sum (V.imap (\j u -> eval_A i j * u) us)
+
+      eval_A i j = 1 / fromIntegral r
+        where
+          r = u + (i+1)
+          u = t `shiftR` 1
+          t = n * (n+1)
+          n = i+j
+
diff --git a/benchmarks/Algo/Tridiag.hs b/benchmarks/Algo/Tridiag.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Algo/Tridiag.hs
@@ -0,0 +1,20 @@
+module Algo.Tridiag ( tridiag ) where
+
+import Data.Vector.Unboxed as V
+
+tridiag :: (Vector Double, Vector Double, Vector Double, Vector Double)
+            -> Vector Double
+{-# NOINLINE tridiag #-}
+tridiag (as,bs,cs,ds) = xs
+    where
+      (cs',ds') = V.unzip
+                $ V.prescanl' modify (0,0)
+                $ V.zip (V.zip as bs) (V.zip cs ds)
+
+      modify (c',d') ((a,b),(c,d)) = 
+                   let id = 1 / (b - c'*a)
+                   in
+                   id `seq` (c*id, (d-d'*a)*id)
+
+      xs = V.prescanr' (\(c,d) x' -> d - c*x') 0 (V.zip cs' ds')
+
diff --git a/benchmarks/LICENSE b/benchmarks/LICENSE
new file mode 100644
--- /dev/null
+++ b/benchmarks/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2008-2009, Roman Leshchinskiy
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+ 
+- Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+ 
+- Neither name of the University nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission. 
+
+THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF
+GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
diff --git a/benchmarks/Main.hs b/benchmarks/Main.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Main.hs
@@ -0,0 +1,46 @@
+module Main where
+
+import Criterion.Main
+
+import Algo.ListRank  (listRank)
+import Algo.Rootfix   (rootfix)
+import Algo.Leaffix   (leaffix)
+import Algo.AwShCC    (awshcc)
+import Algo.HybCC     (hybcc)
+import Algo.Quickhull (quickhull)
+import Algo.Spectral  ( spectral )
+import Algo.Tridiag   ( tridiag )
+
+import TestData.ParenTree ( parenTree )
+import TestData.Graph     ( randomGraph )
+import TestData.Random    ( randomVector )
+
+import Data.Vector.Unboxed ( Vector )
+
+size :: Int
+size = 100000
+
+main = lparens `seq` rparens `seq`
+       nodes `seq` edges1 `seq` edges2 `seq`
+       do
+         as <- randomVector size :: IO (Vector Double)
+         bs <- randomVector size :: IO (Vector Double)
+         cs <- randomVector size :: IO (Vector Double)
+         ds <- randomVector size :: IO (Vector Double)
+         sp <- randomVector (floor $ sqrt $ fromIntegral size)
+                                 :: IO (Vector Double)
+         as `seq` bs `seq` cs `seq` ds `seq` sp `seq`
+           defaultMain [ bench "listRank"  $ whnf listRank size
+                       , bench "rootfix"   $ whnf rootfix (lparens, rparens)
+                       , bench "leaffix"   $ whnf leaffix (lparens, rparens)
+                       , bench "awshcc"    $ whnf awshcc (nodes, edges1, edges2)
+                       , bench "hybcc"     $ whnf hybcc  (nodes, edges1, edges2)
+                       , bench "quickhull" $ whnf quickhull (as,bs)
+                       , bench "spectral"  $ whnf spectral sp
+                       , bench "tridiag"   $ whnf tridiag (as,bs,cs,ds)
+                       ]
+  where
+    (lparens, rparens) = parenTree size
+    (nodes, edges1, edges2) = randomGraph size
+    
+
diff --git a/benchmarks/Setup.hs b/benchmarks/Setup.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+main = defaultMain
+
diff --git a/benchmarks/TestData/Graph.hs b/benchmarks/TestData/Graph.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/TestData/Graph.hs
@@ -0,0 +1,45 @@
+module TestData.Graph ( randomGraph )
+where
+
+import System.Random.MWC
+import qualified Data.Array.ST as STA
+import qualified Data.Vector.Unboxed as V
+
+import Control.Monad.ST ( ST, runST )
+
+randomGraph :: Int -> (Int, V.Vector Int, V.Vector Int)
+randomGraph e
+  = runST (
+    do
+      g <- create
+      arr <- STA.newArray (0,n-1) [] :: ST s (STA.STArray s Int [Int])
+      addRandomEdges n g arr e
+      xs <- STA.getAssocs arr
+      let (as,bs) = unzip [(i,j) | (i,js) <- xs, j <- js ]
+      return (n, V.fromListN (length as) as, V.fromListN (length bs) bs)
+    )
+  where
+    n = e `div` 10
+
+addRandomEdges :: Int -> Gen s -> STA.STArray s Int [Int] -> Int -> ST s ()
+addRandomEdges n g arr = fill
+  where
+    fill 0 = return ()
+    fill e
+      = do
+          m <- random_index
+          n <- random_index
+          let lo = min m n
+              hi = max m n
+          ns <- STA.readArray arr lo
+          if lo == hi || hi `elem` ns
+            then fill e
+            else do
+                   STA.writeArray arr lo (hi:ns)
+                   fill (e-1)
+
+    random_index = do
+                     x <- uniform g
+                     let i = floor ((x::Double) * toEnum n)
+                     if i == n then return 0 else return i
+
diff --git a/benchmarks/TestData/ParenTree.hs b/benchmarks/TestData/ParenTree.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/TestData/ParenTree.hs
@@ -0,0 +1,20 @@
+module TestData.ParenTree where
+
+import qualified Data.Vector.Unboxed as V
+
+parenTree :: Int -> (V.Vector Int, V.Vector Int)
+parenTree n = case go ([],[]) 0 (if even n then n else n+1) of
+               (ls,rs) -> (V.fromListN (length ls) (reverse ls),
+                           V.fromListN (length rs) (reverse rs))
+  where
+    go (ls,rs) i j = case j-i of
+                       0 -> (ls,rs)
+                       2 -> (ls',rs')
+                       d -> let k = ((d-2) `div` 4) * 2
+                            in
+                            go (go (ls',rs') (i+1) (i+1+k)) (i+1+k) (j-1)
+      where
+        ls' = i:ls
+        rs' = j-1:rs
+
+
diff --git a/benchmarks/TestData/Random.hs b/benchmarks/TestData/Random.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/TestData/Random.hs
@@ -0,0 +1,16 @@
+module TestData.Random ( randomVector ) where
+
+import qualified Data.Vector.Unboxed as V
+
+import System.Random.MWC
+import Control.Monad.ST ( runST )
+
+randomVector :: (Variate a, V.Unbox a) => Int -> IO (V.Vector a)
+randomVector n = withSystemRandom $ \g ->
+  do
+    xs <- sequence $ replicate n $ uniform g
+    io (return $ V.fromListN n xs)
+  where
+    io :: IO a -> IO a
+    io = id
+
diff --git a/benchmarks/vector-benchmarks.cabal b/benchmarks/vector-benchmarks.cabal
new file mode 100644
--- /dev/null
+++ b/benchmarks/vector-benchmarks.cabal
@@ -0,0 +1,37 @@
+Name:           vector-benchmarks
+Version:        0.6
+License:        BSD3
+License-File:   LICENSE
+Author:         Roman Leshchinskiy <rl@cse.unsw.edu.au>
+Maintainer:     Roman Leshchinskiy <rl@cse.unsw.edu.au>
+Copyright:      (c) Roman Leshchinskiy 2010
+Cabal-Version:  >= 1.2
+Build-Type:     Simple
+
+Executable algorithms
+  Main-Is: Main.hs
+
+  Build-Depends: base >= 2 && < 5, array,
+                 criterion >= 0.5 && < 0.6,
+                 mwc-random >= 0.5 && < 0.6,
+                 vector >= 0.6 && < 0.7
+
+  if impl(ghc<6.13)
+    Ghc-Options: -finline-if-enough-args -fno-method-sharing
+  
+  Ghc-Options: -O2
+
+  Other-Modules:
+        Algo.ListRank
+        Algo.Rootfix
+        Algo.Leaffix
+        Algo.AwShCC
+        Algo.HybCC
+        Algo.Quickhull
+        Algo.Spectral
+        Algo.Tridiag
+
+        TestData.ParenTree
+        TestData.Graph
+        TestData.Random
+
diff --git a/internal/GenUnboxTuple.hs b/internal/GenUnboxTuple.hs
--- a/internal/GenUnboxTuple.hs
+++ b/internal/GenUnboxTuple.hs
@@ -157,9 +157,9 @@
       = (pat "MV" <+> tuple vars,
          mk_do [qM rec <+> vs <+> v | vs <- varss | v <- vars] empty)
 
-    gen_unsafeCopy rec
-      = (patn "MV" 1 <+> patn "MV" 2,
-         mk_do [qM rec <+> vs <> char '1' <+> vs <> char '2' | vs <- varss]
+    gen_unsafeCopy c q rec
+      = (patn "MV" 1 <+> patn c 2,
+         mk_do [q rec <+> vs <> char '1' <+> vs <> char '2' | vs <- varss]
                empty)
 
     gen_unsafeGrow rec
@@ -183,11 +183,11 @@
                $ text "return" <+> tuple vars)
 
     gen_elemseq rec
-      = (char '_' <+> tuple vars <+> var 'x',
-         vcat [qG rec <+> parens (text "undefined :: Vector" <+> v)
-                      <+> v <+> char '$' | v <- vars]
-         <+> var 'x')
-
+      = (char '_' <+> tuple vars,
+         vcat $ r : [char '.' <+> r | r <- rs])
+      where
+        r : rs = [qG rec <+> parens (text "undefined :: Vector" <+> v)
+                         <+> v | v <- vars]
 
     mk_do cmds ret = hang (text "do")
                           2
@@ -209,11 +209,12 @@
                       ,("basicUnsafeWrite",       gen_unsafeWrite)
                       ,("basicClear",             gen_clear)
                       ,("basicSet",               gen_set)
-                      ,("basicUnsafeCopy",        gen_unsafeCopy)
+                      ,("basicUnsafeCopy",        gen_unsafeCopy "MV" qM)
                       ,("basicUnsafeGrow",        gen_unsafeGrow)]
 
     methods_Vector  = [("unsafeFreeze",           gen_unsafeFreeze)
                       ,("basicLength",            gen_length "V")
                       ,("basicUnsafeSlice",       gen_unsafeSlice "G" "V")
                       ,("basicUnsafeIndexM",      gen_basicUnsafeIndexM)
+                      ,("basicUnsafeCopy",        gen_unsafeCopy "V" qG)
                       ,("elemseq",                gen_elemseq)]
diff --git a/internal/unbox-tuple-instances b/internal/unbox-tuple-instances
--- a/internal/unbox-tuple-instances
+++ b/internal/unbox-tuple-instances
@@ -80,10 +80,15 @@
           a <- G.basicUnsafeIndexM as i_
           b <- G.basicUnsafeIndexM bs i_
           return (a, b)
+  {-# INLINE basicUnsafeCopy  #-}
+  basicUnsafeCopy (MV_2 n_1 as1 bs1) (V_2 n_2 as2 bs2)
+      = do
+          G.basicUnsafeCopy as1 as2
+          G.basicUnsafeCopy bs1 bs2
   {-# INLINE elemseq  #-}
-  elemseq _ (a, b) x_
-      = G.elemseq (undefined :: Vector a) a $
-        G.elemseq (undefined :: Vector b) b $ x_
+  elemseq _ (a, b)
+      = G.elemseq (undefined :: Vector a) a
+        . G.elemseq (undefined :: Vector b) b
 #endif
 #ifdef DEFINE_MUTABLE
 zip :: (Unbox a, Unbox b) => MVector s a ->
@@ -211,11 +216,17 @@
           b <- G.basicUnsafeIndexM bs i_
           c <- G.basicUnsafeIndexM cs i_
           return (a, b, c)
+  {-# INLINE basicUnsafeCopy  #-}
+  basicUnsafeCopy (MV_3 n_1 as1 bs1 cs1) (V_3 n_2 as2 bs2 cs2)
+      = do
+          G.basicUnsafeCopy as1 as2
+          G.basicUnsafeCopy bs1 bs2
+          G.basicUnsafeCopy cs1 cs2
   {-# INLINE elemseq  #-}
-  elemseq _ (a, b, c) x_
-      = G.elemseq (undefined :: Vector a) a $
-        G.elemseq (undefined :: Vector b) b $
-        G.elemseq (undefined :: Vector c) c $ x_
+  elemseq _ (a, b, c)
+      = G.elemseq (undefined :: Vector a) a
+        . G.elemseq (undefined :: Vector b) b
+        . G.elemseq (undefined :: Vector c) c
 #endif
 #ifdef DEFINE_MUTABLE
 zip3 :: (Unbox a, Unbox b, Unbox c) => MVector s a ->
@@ -375,12 +386,22 @@
           c <- G.basicUnsafeIndexM cs i_
           d <- G.basicUnsafeIndexM ds i_
           return (a, b, c, d)
+  {-# INLINE basicUnsafeCopy  #-}
+  basicUnsafeCopy (MV_4 n_1 as1 bs1 cs1 ds1) (V_4 n_2 as2
+                                                      bs2
+                                                      cs2
+                                                      ds2)
+      = do
+          G.basicUnsafeCopy as1 as2
+          G.basicUnsafeCopy bs1 bs2
+          G.basicUnsafeCopy cs1 cs2
+          G.basicUnsafeCopy ds1 ds2
   {-# INLINE elemseq  #-}
-  elemseq _ (a, b, c, d) x_
-      = G.elemseq (undefined :: Vector a) a $
-        G.elemseq (undefined :: Vector b) b $
-        G.elemseq (undefined :: Vector c) c $
-        G.elemseq (undefined :: Vector d) d $ x_
+  elemseq _ (a, b, c, d)
+      = G.elemseq (undefined :: Vector a) a
+        . G.elemseq (undefined :: Vector b) b
+        . G.elemseq (undefined :: Vector c) c
+        . G.elemseq (undefined :: Vector d) d
 #endif
 #ifdef DEFINE_MUTABLE
 zip4 :: (Unbox a, Unbox b, Unbox c, Unbox d) => MVector s a ->
@@ -579,13 +600,25 @@
           d <- G.basicUnsafeIndexM ds i_
           e <- G.basicUnsafeIndexM es i_
           return (a, b, c, d, e)
+  {-# INLINE basicUnsafeCopy  #-}
+  basicUnsafeCopy (MV_5 n_1 as1 bs1 cs1 ds1 es1) (V_5 n_2 as2
+                                                          bs2
+                                                          cs2
+                                                          ds2
+                                                          es2)
+      = do
+          G.basicUnsafeCopy as1 as2
+          G.basicUnsafeCopy bs1 bs2
+          G.basicUnsafeCopy cs1 cs2
+          G.basicUnsafeCopy ds1 ds2
+          G.basicUnsafeCopy es1 es2
   {-# INLINE elemseq  #-}
-  elemseq _ (a, b, c, d, e) x_
-      = G.elemseq (undefined :: Vector a) a $
-        G.elemseq (undefined :: Vector b) b $
-        G.elemseq (undefined :: Vector c) c $
-        G.elemseq (undefined :: Vector d) d $
-        G.elemseq (undefined :: Vector e) e $ x_
+  elemseq _ (a, b, c, d, e)
+      = G.elemseq (undefined :: Vector a) a
+        . G.elemseq (undefined :: Vector b) b
+        . G.elemseq (undefined :: Vector c) c
+        . G.elemseq (undefined :: Vector d) d
+        . G.elemseq (undefined :: Vector e) e
 #endif
 #ifdef DEFINE_MUTABLE
 zip5 :: (Unbox a,
@@ -833,14 +866,28 @@
           e <- G.basicUnsafeIndexM es i_
           f <- G.basicUnsafeIndexM fs i_
           return (a, b, c, d, e, f)
+  {-# INLINE basicUnsafeCopy  #-}
+  basicUnsafeCopy (MV_6 n_1 as1 bs1 cs1 ds1 es1 fs1) (V_6 n_2 as2
+                                                              bs2
+                                                              cs2
+                                                              ds2
+                                                              es2
+                                                              fs2)
+      = do
+          G.basicUnsafeCopy as1 as2
+          G.basicUnsafeCopy bs1 bs2
+          G.basicUnsafeCopy cs1 cs2
+          G.basicUnsafeCopy ds1 ds2
+          G.basicUnsafeCopy es1 es2
+          G.basicUnsafeCopy fs1 fs2
   {-# INLINE elemseq  #-}
-  elemseq _ (a, b, c, d, e, f) x_
-      = G.elemseq (undefined :: Vector a) a $
-        G.elemseq (undefined :: Vector b) b $
-        G.elemseq (undefined :: Vector c) c $
-        G.elemseq (undefined :: Vector d) d $
-        G.elemseq (undefined :: Vector e) e $
-        G.elemseq (undefined :: Vector f) f $ x_
+  elemseq _ (a, b, c, d, e, f)
+      = G.elemseq (undefined :: Vector a) a
+        . G.elemseq (undefined :: Vector b) b
+        . G.elemseq (undefined :: Vector c) c
+        . G.elemseq (undefined :: Vector d) d
+        . G.elemseq (undefined :: Vector e) e
+        . G.elemseq (undefined :: Vector f) f
 #endif
 #ifdef DEFINE_MUTABLE
 zip6 :: (Unbox a,
diff --git a/tests/Tests/Vector.hs b/tests/Tests/Vector.hs
--- a/tests/Tests/Vector.hs
+++ b/tests/Tests/Vector.hs
@@ -81,7 +81,7 @@
         'prop_length, 'prop_null,
 
         'prop_empty, 'prop_singleton, 'prop_replicate,
-        'prop_cons, 'prop_snoc, 'prop_append, 'prop_copy, 'prop_generate,
+        'prop_cons, 'prop_snoc, 'prop_append, 'prop_force, 'prop_generate,
 
         'prop_head, 'prop_last, 'prop_index,
         'prop_unsafeHead, 'prop_unsafeLast, 'prop_unsafeIndex,
@@ -131,7 +131,7 @@
     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_force     :: P (v a -> v a)        = V.force `eq` id
     prop_generate  :: P (Int -> (Int -> a) -> v a)
               = (\n _ -> n < 1000) ===> V.generate `eq` generate
 
diff --git a/tests/vector-tests.cabal b/tests/vector-tests.cabal
--- a/tests/vector-tests.cabal
+++ b/tests/vector-tests.cabal
@@ -1,5 +1,5 @@
 Name:           vector-tests
-Version:        0.5
+Version:        0.6
 License:        BSD3
 License-File:   LICENSE
 Author:         Max Bolingbroke, Roman Leshchinskiy
@@ -27,7 +27,8 @@
               TypeFamilies,
               TemplateHaskell
 
-  Build-Depends: base >= 4 && < 5, template-haskell, vector, random,
+  Build-Depends: base >= 4 && < 5, template-haskell, vector >= 0.6 && < 0.7,
+                 random,
                  QuickCheck >= 2, test-framework, test-framework-quickcheck2
 
   -- Don't let fusion occur or GHC will make our tests less informative in some cases :-)
diff --git a/vector.cabal b/vector.cabal
--- a/vector.cabal
+++ b/vector.cabal
@@ -1,17 +1,18 @@
 Name:           vector
-Version:        0.5
+Version:        0.6
 License:        BSD3
 License-File:   LICENSE
 Author:         Roman Leshchinskiy <rl@cse.unsw.edu.au>
 Maintainer:     Roman Leshchinskiy <rl@cse.unsw.edu.au>
 Copyright:      (c) Roman Leshchinskiy 2008-2010
 Homepage:       http://code.haskell.org/vector
+Bug-Reports:    http://trac.haskell.org/vector
 Category:       Data, Data Structures
 Synopsis:       Efficient Arrays
 Description:
         .
-        An efficient implementation of Int-indexed arrays with a powerful loop
-        fusion framework.
+        An efficient implementation of Int-indexed arrays (both mutable
+        and immutable), with a powerful loop fusion optimization framework .
         .
         It is structured as follows:
         .
@@ -28,19 +29,31 @@
         .
         [@Data.Vector.Generic@] Generic interface to the vector types.
         .
-        Changes since version 0.4.2
+        There is also a (draft) tutorial on common uses of vector.
         .
-        * Unboxed vectors of primitive types and tuples
+        * <http://haskell.org/haskellwiki/Numeric_Haskell:_A_Vector_Tutorial>
         .
-        * Redesigned interface between mutable and immutable vectors (now
-          with the popular @unsafeFreeze@ primitive)
+        Please use the project trac to submit bug reports and feature
+        requests.
         .
-        * Many new combinators
+        * <http://trac.haskell.org/vector>
         .
-        * Significant performance improvements
+        Changes since version 0.5
         .
+        * More efficient representation of @Storable@ vectors
+        .
+        * Block copy operations used when possible
+        .
+        * @Typeable@ and @Data@ instances
+        .
+        * Monadic combinators (@replicateM@, @mapM@ etc.)
+        .
+        * Better support for recycling (see @create@ and @modify@)
+        .
+        * Performance improvements
+        .
 
-Cabal-Version:  >= 1.2
+Cabal-Version:  >= 1.2.3
 Build-Type:     Simple
 
 Extra-Source-Files:
@@ -52,6 +65,21 @@
       tests/Utilities.hs
       tests/Tests/Stream.hs
       tests/Tests/Vector.hs
+      benchmarks/vector-benchmarks.cabal
+      benchmarks/LICENSE
+      benchmarks/Setup.hs
+      benchmarks/Main.hs
+      benchmarks/Algo/AwShCC.hs
+      benchmarks/Algo/HybCC.hs
+      benchmarks/Algo/Leaffix.hs
+      benchmarks/Algo/ListRank.hs
+      benchmarks/Algo/Quickhull.hs
+      benchmarks/Algo/Rootfix.hs
+      benchmarks/Algo/Spectral.hs
+      benchmarks/Algo/Tridiag.hs
+      benchmarks/TestData/Graph.hs
+      benchmarks/TestData/ParenTree.hs
+      benchmarks/TestData/Random.hs
       internal/GenUnboxTuple.hs
       internal/unbox-tuple-instances
 
@@ -71,7 +99,7 @@
 
 
 Library
-  Extensions: CPP
+  Extensions: CPP, DeriveDataTypeable
   Exposed-Modules:
         Data.Vector.Internal.Check
 
@@ -81,6 +109,7 @@
         Data.Vector.Fusion.Stream
 
         Data.Vector.Generic.Mutable
+        Data.Vector.Generic.Base
         Data.Vector.Generic.New
         Data.Vector.Generic
 
@@ -104,10 +133,10 @@
   Install-Includes:
         vector.h
 
-  Build-Depends: base >= 2 && < 5, ghc >= 6.9, primitive >= 0.2 && < 0.3
+  Build-Depends: base >= 4 && < 5, ghc >= 6.9, primitive >= 0.3 && < 0.4
 
   if impl(ghc<6.13)
-    Ghc-Options: -finline-if-enough-args
+    Ghc-Options: -finline-if-enough-args -fno-method-sharing
   
   Ghc-Options: -O2
 
