diff --git a/Data/Array/Repa/Index.hs b/Data/Array/Repa/Index.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Repa/Index.hs
@@ -0,0 +1,145 @@
+{-# LANGUAGE TypeOperators, FlexibleInstances, ScopedTypeVariables #-}
+
+-- | Index types.
+module Data.Array.Repa.Index
+	(
+	-- * Index types
+	  Z	(..)
+	, (:.)	(..)
+
+	-- * Common dimensions.
+	, DIM0
+	, DIM1
+	, DIM2
+	, DIM3
+	, DIM4
+	, DIM5)
+where
+import Data.Array.Repa.Shape
+import GHC.Base 		(quotInt, remInt)
+
+stage	= "Data.Array.Repa.Index"
+
+-- | An index of dimension zero
+data Z	= Z
+	deriving (Show, Eq, Ord)
+
+-- | Our index type, used for both shapes and indices.
+infixl 3 :.
+data tail :. head
+	= tail :. head
+	deriving (Show, Eq, Ord)
+
+-- Common dimensions
+type DIM0	= Z
+type DIM1	= DIM0 :. Int
+type DIM2	= DIM1 :. Int
+type DIM3	= DIM2 :. Int
+type DIM4	= DIM3 :. Int
+type DIM5	= DIM4 :. Int
+
+
+-- Shape ------------------------------------------------------------------------------------------
+instance Shape Z where
+	{-# INLINE rank #-}
+	rank _			= 0
+
+	{-# INLINE zeroDim #-}
+	zeroDim			= Z
+
+	{-# INLINE unitDim #-}
+	unitDim			= Z
+
+	{-# INLINE intersectDim #-}
+	intersectDim _ _	= Z
+
+	{-# INLINE addDim #-}
+	addDim _ _		= Z
+
+	{-# INLINE size #-}
+	size _			= 1
+
+	{-# INLINE sizeIsValid #-}
+	sizeIsValid _		= True
+
+
+	{-# INLINE toIndex #-}
+	toIndex _ _		= 0
+
+	{-# INLINE fromIndex #-}
+	fromIndex _ _		= Z
+
+
+	{-# INLINE inShapeRange #-}
+	inShapeRange Z Z Z	= True
+
+	listOfShape _		= []
+	shapeOfList []		= Z
+	shapeOfList _		= error $ stage ++ ".fromList: non-empty list when converting to Z."
+
+	{-# INLINE deepSeq #-}
+	deepSeq Z x		= x
+
+
+instance Shape sh => Shape (sh :. Int) where
+	{-# INLINE rank #-}
+	rank   (sh  :. _)
+		= rank sh + 1
+
+	{-# INLINE zeroDim #-}
+	zeroDim = zeroDim :. 0
+
+	{-# INLINE unitDim #-}
+	unitDim = unitDim :. 1
+
+	{-# INLINE intersectDim #-}
+	intersectDim (sh1 :. n1) (sh2 :. n2)
+		= (intersectDim sh1 sh2 :. (min n1 n2))
+
+	{-# INLINE addDim #-}
+	addDim (sh1 :. n1) (sh2 :. n2)
+		= addDim sh1 sh2 :. (n1 + n2)
+
+	{-# INLINE size #-}
+	size  (sh1 :. n)
+		= size sh1 * n
+
+	{-# INLINE sizeIsValid #-}
+	sizeIsValid (sh1 :. n)
+		| size sh1 > 0
+		= n <= maxBound `div` size sh1
+
+		| otherwise
+		= False
+
+	{-# INLINE toIndex #-}
+	toIndex (sh1 :. sh2) (sh1' :. sh2')
+		= toIndex sh1 sh1' * sh2 + sh2'
+
+	{-# INLINE fromIndex #-}
+	fromIndex (ds :. d) n
+	 	= fromIndex ds (n `quotInt` d) :. r
+		where
+		-- If we assume that the index is in range, there is no point
+		-- in computing the remainder for the highest dimension since
+		-- n < d must hold. This saves one remInt per element access which
+		-- is quite a big deal.
+		r 	| rank ds == 0	= n
+			| otherwise	= n `remInt` d
+
+	{-# INLINE inShapeRange #-}
+	inShapeRange (zs :. z) (sh1 :. n1) (sh2 :. n2)
+		= (n2 >= z) && (n2 < n1) && (inShapeRange zs sh1 sh2)
+
+
+       	listOfShape (sh :. n)
+	 = n : listOfShape sh
+
+	shapeOfList xx
+	 = case xx of
+		[]	-> error $ stage ++ ".toList: empty list when converting to  (_ :. Int)"
+		x:xs	-> shapeOfList xs :. x
+
+	{-# INLINE deepSeq #-}
+	deepSeq (sh :. n) x = deepSeq sh (n `seq` x)
+
diff --git a/Data/Array/Repa/Shape.hs b/Data/Array/Repa/Shape.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Repa/Shape.hs
@@ -0,0 +1,82 @@
+{-# LANGUAGE RankNTypes #-}
+
+-- | Class of types that can be used as array shapes and indices.
+module Data.Array.Repa.Shape
+	( Shape(..)
+        , inShape
+        , showShape )
+where
+
+-- Shape ------------------------------------------------------------------------------------------
+-- | Class of types that can be used as array shapes and indices.
+class Eq sh => Shape sh where
+
+	-- | Get the number of dimensions in a shape.
+	rank	:: sh -> Int
+
+	-- | The shape of an array of size zero, with a particular dimensionality.
+	zeroDim	:: sh
+
+	-- | The shape of an array with size one, with a particular dimensionality.
+	unitDim :: sh
+
+	-- | Compute the intersection of two shapes.
+	intersectDim :: sh -> sh -> sh
+
+	-- | Add the coordinates of two shapes componentwise
+	addDim  :: sh -> sh -> sh
+
+	-- | Get the total number of elements in an array with this shape.
+	size	:: sh -> Int
+
+	-- | Check whether this shape is small enough so that its flat
+	--	indices an be represented as `Int`. If this returns `False` then your
+	--	array is too big. Mostly used for writing QuickCheck tests.
+	sizeIsValid :: sh -> Bool
+
+
+	-- | Convert an index into its equivalent flat, linear, row-major version.
+	toIndex :: sh	-- ^ Shape of the array.
+		-> sh 	-- ^ Index into the array.
+		-> Int
+
+	-- | Inverse of `toIndex`.
+	fromIndex
+		:: sh 	-- ^ Shape of the array.
+		-> Int 	-- ^ Index into linear representation.
+		-> sh
+
+	-- | Check whether an index is within a given shape.
+	inShapeRange
+		:: sh 	-- ^ Start index for range.
+		-> sh 	-- ^ Final index for range.
+		-> sh 	-- ^ Index to check for.
+		-> Bool
+
+	-- | Convert a shape into its list of dimensions.
+	listOfShape	:: sh -> [Int]
+
+	-- | Convert a list of dimensions to a shape
+	shapeOfList	:: [Int] -> sh
+
+	-- | Ensure that a shape is completely evaluated.
+	infixr 0 `deepSeq`
+	deepSeq :: sh -> a -> a
+
+
+-- | Check whether an index is a part of a given shape.
+inShape :: forall sh
+	.  Shape sh
+	=> sh 		-- ^ Shape of the array.
+	-> sh		-- ^ Index.
+	-> Bool
+
+{-# INLINE inShape #-}
+inShape sh ix
+	= inShapeRange zeroDim sh ix
+
+
+-- | Nicely format a shape as a string
+showShape :: Shape sh => sh -> String
+showShape = foldr (\sh str -> str ++ " :. " ++ show sh) "Z" . listOfShape
+
diff --git a/Data/ExtShape.hs b/Data/ExtShape.hs
new file mode 100644
--- /dev/null
+++ b/Data/ExtShape.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeOperators #-}
+
+-- | Additional functions on shapes
+
+module Data.ExtShape where
+
+import Data.Array.Repa.Index
+import Data.Array.Repa.Shape
+
+
+
+-- | A number of additional operations that are useful together with
+-- 'PrimitiveArray's.
+
+class (Eq sh, Shape sh) => ExtShape sh where
+
+  -- | subtract the right coordinates from the left. Does not check if the
+  -- resulting shape make sense.
+
+  subDim :: sh -> sh -> sh
+
+  -- | Given an index and an extend, return a list of all indices. For
+  -- @rangeList (Z:.3) (Z:.2)@ this returns @[(Z:.3), (Z:.4), (Z:.5)]@.
+
+  rangeList :: sh -> sh -> [sh]
+
+
+
+instance ExtShape Z where
+  subDim _ _ = Z
+  {-# INLINE subDim #-}
+  rangeList _ _ = [Z]
+  {-# INLINE rangeList #-}
+
+instance ExtShape sh => ExtShape (sh:.Int) where
+  subDim (sh1:.n1) (sh2:.n2) = subDim sh1 sh2 :. (n1-n2)
+  {-# INLINE subDim #-}
+  rangeList (sh1:.n1) (sh2:.n2) = [sh:.n | sh <- rangeList sh1 sh2, n <- [n1 .. (n1+n2) ] ]
+  {-# INLINE rangeList #-}
+
diff --git a/Data/PrimitiveArray.hs b/Data/PrimitiveArray.hs
--- a/Data/PrimitiveArray.hs
+++ b/Data/PrimitiveArray.hs
@@ -1,46 +1,164 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 
--- | Primitive arrays with a small set of operations. Modelled after repa
--- arrays and indexing.
---
--- Array indexing is between [i..j] per dimension.
+-- | Vastly extended primitive arrays. Some basic ideas are now modeled after
+-- the vector package, especially the monadic mutable / pure immutable array
+-- system. There are eight flavors of arrays among three axes: mutable/pure +
+-- boxed/unboxed + zero-based/lower-bound.
 --
--- All operations are UNSAFE. In interpreted code, "assert" provides a safety
--- net.
+-- NOTE all operations in MPrimArrayOps and PrimArrayOps are highly unsafe. No
+-- bounds-checking is performed at all.
 
 module Data.PrimitiveArray where
 
-import Control.Monad.Primitive (PrimMonad)
-import Data.Array.Repa.Shape (Shape)
+import Data.Array.Repa.Index
+import Data.Array.Repa.Shape
+import Data.Primitive.Types
+import Data.Primitive
+import Control.Monad.ST
+import Control.Monad
+import Control.Monad.Primitive
+import System.IO.Unsafe
 import Control.Exception (assert)
 
+import Data.ExtShape
 
 
-class Shape sh => PrimArrayOps sh elm where
-  data PrimArray sh elm :: *
-  unsafeIndex :: PrimArray sh elm -> sh -> elm
-  bounds :: PrimArray sh elm -> (sh,sh)
-  inBounds :: PrimArray sh elm -> sh -> Bool
-  fromAssocs :: sh -> sh -> elm -> [(sh,elm)] -> PrimArray sh elm
-  assocs :: PrimArray sh elm -> [(sh,elm)]
 
-class (PrimMonad m, Shape sh) => PrimArrayOpsM sh elm m where
-  data PrimArrayM sh elm m :: *
-  readM :: PrimArrayM sh elm m -> sh -> m elm
-  writeM :: PrimArrayM sh elm m -> sh -> elm -> m ()
-  -- | Create a monadic array from a list of associations
-  fromAssocsM :: sh -> sh -> elm -> [(sh,elm)] -> m (PrimArrayM sh elm m)
-  unsafeFreezeM :: PrimArrayM sh elm m -> m (PrimArray sh elm)
-  boundsM :: PrimArrayM sh elm m -> (sh,sh)
-  inBoundsM :: PrimArrayM sh elm m -> sh -> Bool
+-- | The core set of operations for monadic arrays.
 
+class (Shape sh, ExtShape sh) => MPrimArrayOps marr sh elm where
 
+  -- | Return the bounds of the array. All bounds are inclusive, as in
+  -- @[lb..ub]@
 
--- * Helper functions
+  boundsM :: marr s sh elm -> (sh,sh)
 
-(!) :: PrimArrayOps sh elm => PrimArray sh elm -> sh -> elm
-(!) pa idx = assert (inBounds pa idx) $ unsafeIndex pa idx
+  -- | Given lower and upper bounds and a list of /all/ elements, produce a
+  -- mutable array.
+
+  fromListM :: PrimMonad m => sh -> sh -> [elm] -> m (marr (PrimState m) sh elm)
+
+  -- | Creates a new array with the given bounds with each element within the
+  -- array being in a random state.
+
+  newM :: PrimMonad m => sh -> sh -> m (marr (PrimState m) sh elm)
+
+  -- | Creates a new array with all elements being equal to 'elm'.
+
+  newWithM :: PrimMonad m => sh -> sh -> elm -> m (marr (PrimState m) sh elm)
+
+  -- | Reads a single element in the array.
+
+  readM :: PrimMonad m => marr (PrimState m) sh elm -> sh -> m elm
+
+  -- | Writes a single element in the array.
+
+  writeM :: PrimMonad m => marr (PrimState m) sh elm -> sh -> elm -> m ()
+
+
+
+-- | Used to connect each immutable array with one mutable array.
+
+type family MutArray (v :: * -> * -> * ) :: * -> * -> * -> *
+
+
+
+-- | The core set of functions on immutable arrays.
+
+class (Shape sh, ExtShape sh, MPrimArrayOps (MutArray arr) sh elm) => PrimArrayOps arr sh elm where
+
+  -- | Returns the bounds of an immutable array, again inclusive bounds: @ [lb..ub] @.
+
+  bounds :: arr sh elm -> (sh,sh)
+
+  -- | Freezes a mutable array an returns its immutable version. This operation
+  -- is /O(1)/ and both arrays share the same memory. Do not use the mutable
+  -- array afterwards.
+
+  freeze :: PrimMonad m => MutArray arr (PrimState m) sh elm -> m (arr sh elm)
+
+  -- | Extract a single element from the array. Generally unsafe as not
+  -- bounds-checking is performed.
+
+  index :: arr sh elm -> sh -> elm
+
+
+
+-- | Infix index operator. Performs minimal bounds-checking using assert in
+-- non-optimized code.
+
+(!) :: PrimArrayOps arr sh elm => arr sh elm -> sh -> elm
+(!) arr idx = assert (inBounds arr idx) $ index arr idx
 {-# INLINE (!) #-}
+
+-- | Returns true if the index is valid for the array.
+--
+-- TODO can't give a typedef
+
+inBoundsM :: MPrimArrayOps marr sh elm => marr s sh elm -> sh -> Bool
+inBoundsM marr idx = let (lb,ub) = boundsM marr in inShapeRange lb ub idx
+{-# INLINE inBoundsM #-}
+
+-- | Given two arrays with the same dimensionality, their respective starting
+-- index, and how many steps to go in each dimension (in terms of a dimension
+-- again), determine if the multidimensional slices have the same value at
+-- all positions
+--
+-- TODO specialize for DIM1 (and maybe higher dim's) to use memcmp
+
+sliceEq :: (Eq elm, PrimArrayOps arr sh elm) => arr sh elm -> sh -> arr sh elm -> sh -> sh -> Bool
+sliceEq arr1 k1 arr2 k2 xtnd = assert ((inBounds arr1 k1) && (inBounds arr2 k2) && (inBounds arr1 $ k1 `addDim` xtnd) && (inBounds arr2 $ k2 `addDim` xtnd)) $ and res where
+  res = zipWith (==) xs ys
+  xs = map (index arr1) $ rangeList k1 xtnd
+  ys = map (index arr2) $ rangeList k2 xtnd
+{-# INLINE sliceEq #-}
+
+-- | Construct a mutable primitive array from a lower and an upper bound, a
+-- default element, and a list of associations.
+
+fromAssocsM
+  :: (PrimMonad m, MPrimArrayOps marr sh elm)
+  => sh -> sh -> elm -> [(sh,elm)] -> m (marr (PrimState m) sh elm)
+fromAssocsM lb ub def xs = do
+  ma <- newWithM lb ub def
+  forM_ xs $ \(k,v) -> writeM ma k v
+  return ma
+{-# INLINE fromAssocsM #-}
+
+-- | Return all associations from an array.
+
+assocs :: PrimArrayOps arr sh elm => arr sh elm -> [(sh,elm)]
+assocs arr = map (\k -> (k,index arr k)) $ rangeList lb (ub `subDim` lb) where
+  (lb,ub) = bounds arr
+{-# INLINE assocs #-}
+
+-- | Creates an immutable array from lower and upper bounds and a complete list
+-- of elements.
+
+fromList :: PrimArrayOps arr sh elm => sh -> sh -> [elm] -> arr sh elm
+fromList lb ub xs = runST $ fromListM lb ub xs >>= freeze
+{-# INLINE fromList #-}
+
+-- | Creates an immutable array from lower and upper bounds, a default element,
+-- and a list of associations.
+
+fromAssocs :: PrimArrayOps arr sh elm => sh -> sh -> elm -> [(sh,elm)] -> arr sh elm
+fromAssocs lb ub def xs = runST $ fromAssocsM lb ub def xs >>= freeze
+{-# INLINE fromAssocs #-}
+
+-- | Determines if an index is valid for a given immutable array.
+
+inBounds :: PrimArrayOps arr sh elm => arr sh elm -> sh -> Bool
+inBounds arr idx = let (lb,ub) = bounds arr in inShapeRange lb ub idx
+{-# INLINE inBounds #-}
+
+-- | Returns all elements of an immutable array as a list.
+
+toList :: PrimArrayOps arr sh elm =>  arr sh elm -> [elm]
+toList arr = let (lb,ub) = bounds arr in map ((!) arr) $ rangeList lb $ ub `subDim` lb
+{-# INLINE toList #-}
 
diff --git a/Data/PrimitiveArray/Unboxed.hs b/Data/PrimitiveArray/Unboxed.hs
deleted file mode 100644
--- a/Data/PrimitiveArray/Unboxed.hs
+++ /dev/null
@@ -1,97 +0,0 @@
-{-# LANGUAGE StandaloneDeriving #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE FlexibleInstances #-}
-
-module Data.PrimitiveArray.Unboxed where
-
-import qualified Data.Vector.Unboxed.Mutable as VUM
-import qualified Data.Vector.Unboxed as VU
-import Control.Monad.ST
-import Control.Monad
-import Data.Array.Repa.Shape
-import Control.Exception (assert)
-
-import Data.PrimitiveArray
-
-import Data.Array.Repa.Index
-
-
-
-instance (VU.Unbox elm, Shape sh, Show elm, Show sh) => PrimArrayOps sh elm where
-  -- | An immutable PrimArray has a lower bound (lsh), and upper bound (ush)
-  -- and an upper bound minus unitDim (ush'), returned by bounds
-  data PrimArray sh elm = PrimArray sh sh sh (VU.Vector elm)
-  unsafeIndex (PrimArray lsh ush ush' v) idx = assert (inShapeRange lsh ush idx)
-                                             $ v `VU.unsafeIndex` (toIndex ush idx - toIndex ush lsh)
-  bounds (PrimArray lsh ush ush' _) = (lsh,ush')
-  inBounds (PrimArray lsh ush ush' _) idx = inShapeRange lsh ush idx
-  fromAssocs lsh ush' def xs =
-    let ush = ush' `addDim` unitDim
-    in  PrimArray lsh ush ush'
-        $ VU.replicate (size ush - size lsh) def
-        VU.// map (\(k,v) -> if (inShapeRange lsh ush k)
-                             then (toIndex ush k - toIndex ush lsh,v)
-                             else error $ show (lsh,ush,k,v)
-                  ) xs
-  assocs (PrimArray lsh ush ush' v) = map (\(k,v) -> (fromIndex ush $ k + toIndex ush lsh, v))
-                                    . VU.toList
-                                    . VU.indexed
-                                    $ v
-  {-# INLINE unsafeIndex #-}
-  {-# INLINE bounds #-}
-  {-# INLINE inBounds #-}
-  {-# INLINE fromAssocs #-}
-
-deriving instance (Show elm, Show sh, VU.Unbox elm) => Show (PrimArray sh elm)
-
-deriving instance (Read elm, Read sh, VU.Unbox elm) => Read (PrimArray sh elm)
-
-
-
-instance (VUM.Unbox elm, Shape sh) => PrimArrayOpsM sh elm (ST s) where
-  data PrimArrayM sh elm (ST s) = PrimArrayST sh sh sh (VUM.STVector s elm)
-  readM (PrimArrayST lsh ush ush' v) sh = VUM.unsafeRead v (toIndex ush sh - toIndex ush lsh)
-  writeM (PrimArrayST lsh ush suh' v) sh e = VUM.unsafeWrite v (toIndex ush sh - toIndex ush lsh) e
-  fromAssocsM lsh ush' def xs = do
-    let ush = ush' `addDim` unitDim
-    v <- VUM.new (size ush - size lsh)
-    VUM.set v def
-    forM_ xs $ \(k,e) -> assert (inShapeRange lsh ush k)
-                      $ VUM.unsafeWrite v (toIndex ush k - toIndex ush lsh) e
-    return $ PrimArrayST lsh ush ush' v
-  unsafeFreezeM (PrimArrayST lsh ush ush' v) = do
-    v' <- VU.unsafeFreeze v
-    return $ PrimArray lsh ush ush' v'
-  boundsM (PrimArrayST lsh ush ush' _) = (lsh,ush')
-  inBoundsM (PrimArrayST lsh ush ush' _) idx = inShapeRange lsh ush idx
-  {-# INLINE readM #-}
-  {-# INLINE writeM #-}
-  {-# INLINE fromAssocsM #-}
-  {-# INLINE unsafeFreezeM #-}
-  {-# INLINE boundsM #-}
-  {-# INLINE inBoundsM #-}
-
-instance (VUM.Unbox elm, Shape sh) => PrimArrayOpsM sh elm IO where
-  data PrimArrayM sh elm IO = PrimArrayIO sh sh sh (VUM.IOVector elm)
-  readM (PrimArrayIO lsh ush ush' v) sh = VUM.unsafeRead v (toIndex ush sh - toIndex ush lsh)
-  writeM (PrimArrayIO lsh ush suh' v) sh e = VUM.unsafeWrite v (toIndex ush sh - toIndex ush lsh) e
-  fromAssocsM lsh ush' def xs = do
-    let ush = ush' `addDim` unitDim
-    v <- VUM.new (size ush - size lsh)
-    VUM.set v def
-    forM_ xs $ \(k,e) -> assert (inShapeRange lsh ush k)
-                      $ VUM.unsafeWrite v (toIndex ush k - toIndex ush lsh) e
-    return $ PrimArrayIO lsh ush ush' v
-  unsafeFreezeM (PrimArrayIO lsh ush ush' v) = do
-    v' <- VU.unsafeFreeze v
-    return $ PrimArray lsh ush ush' v'
-  boundsM (PrimArrayIO lsh ush ush' _) = (lsh,ush')
-  inBoundsM (PrimArrayIO lsh ush ush' _) idx = inShapeRange lsh ush idx
-  {-# INLINE readM #-}
-  {-# INLINE writeM #-}
-  {-# INLINE fromAssocsM #-}
-  {-# INLINE unsafeFreezeM #-}
-  {-# INLINE boundsM #-}
-  {-# INLINE inBoundsM #-}
-
diff --git a/Data/PrimitiveArray/Unboxed/Zero.hs b/Data/PrimitiveArray/Unboxed/Zero.hs
new file mode 100644
--- /dev/null
+++ b/Data/PrimitiveArray/Unboxed/Zero.hs
@@ -0,0 +1,70 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+-- | Strict, unboxed arrays of primitive type.
+
+module Data.PrimitiveArray.Unboxed.Zero where
+
+import Control.Monad
+import Data.Array.Repa.Index
+import Data.Array.Repa.Shape
+import Data.Primitive
+import Data.Primitive.Types
+import Control.Exception (assert)
+
+import Data.ExtShape
+import Data.PrimitiveArray
+
+
+
+-- | Monadic arrays of primitive type.
+
+data MArr0 s sh elm = MArr0 !sh {-# UNPACK #-} !(MutableByteArray s)
+
+-- | Immutable arrays of primitive type.
+
+data Arr0 sh elm = Arr0 !sh {-# UNPACK #-} !ByteArray
+
+
+
+type instance MutArray Arr0 = MArr0
+
+-- NOTE inLb, inUb is including bound, while exUb is excluding upper bound.
+-- Differentiates between largest included index, first excluded index.
+
+instance (Shape sh, ExtShape sh, Prim elm) => MPrimArrayOps MArr0 sh elm where
+  boundsM (MArr0 exUb _) = (zeroDim,exUb `subDim` unitDim)
+  fromListM inLb inUb xs = do
+    ma <- newM inLb inUb
+    let exUb = inUb `addDim` unitDim
+    let (MArr0 _ mba) = ma
+    zipWithM_ (\k x -> assert (length xs == size exUb) $ writeByteArray mba k x) [0.. toIndex exUb inUb] xs
+    return ma
+  newM inLb inUb = let exUb = inUb `addDim` unitDim in
+    unless (inLb == zeroDim) (error "MArr0 lb/=zeroDim") >>
+    MArr0 exUb `liftM` newByteArray (size exUb * sizeOf (undefined :: elm))
+  newWithM inLb inUb def = do
+    let exUb = inUb `addDim` unitDim
+    ma <- newM inLb inUb
+    let (MArr0 _ mba) = ma
+    forM_ [0 .. toIndex exUb inUb] $ \k -> writeByteArray mba k def
+    return ma
+  readM (MArr0 exUb mba) idx = assert (inShape exUb idx) $ readByteArray mba (toIndex exUb idx)
+  writeM (MArr0 exUb mba) idx elm = assert (inShape exUb idx) $ writeByteArray mba (toIndex exUb idx) elm
+  {-# INLINE boundsM #-}
+  {-# INLINE fromListM #-}
+  {-# INLINE newM #-}
+  {-# INLINE newWithM #-}
+  {-# INLINE readM #-}
+  {-# INLINE writeM #-}
+
+instance (Shape sh, ExtShape sh, Prim elm) => PrimArrayOps Arr0 sh elm where
+  bounds (Arr0 exUb _) = (zeroDim,exUb `subDim` unitDim)
+  freeze (MArr0 exUb mba) = Arr0 exUb `liftM` unsafeFreezeByteArray mba
+  index (Arr0 exUb ba) idx = assert (inShape exUb idx) $ indexByteArray ba (toIndex exUb idx)
+  {-# INLINE bounds #-}
+  {-# INLINE freeze #-}
+  {-# INLINE index #-}
+
diff --git a/PrimitiveArray.cabal b/PrimitiveArray.cabal
--- a/PrimitiveArray.cabal
+++ b/PrimitiveArray.cabal
@@ -1,5 +1,5 @@
 Name:           PrimitiveArray
-Version:        0.1.1.2
+Version:        0.2.0.0
 License:        BSD3
 License-file:   LICENSE
 Author:         Christian Hoener zu Siederdissen
@@ -13,26 +13,34 @@
 Synopsis:
                 Efficient multidimensional arrays
 Description:
-                This library provides efficient multidimensional arrays. All
-                arrays are 0-based and indexed using repa-shapes.
+                This library provides efficient multidimensional arrays.
                 .
-                Please note that this version only has the name (and author) in
-                common with the previous 0.0.4.0 version. The basic idea of the
-                library remains the same: provide efficient access to immutable
-                arrays.
+                In general all operations are (highly) unsafe, no
+                bounds-checking or other sanity-checking is performed.
+                Operations are aimed toward efficiency as much as possible.
+                Goals of the library are to have arrays according to three
+                ideas: immutable/mutable arrays, strict/lazy arrays,
+                zero-based/lower-bound arrays. Zero-based arrays save one
+                addition on each access if the lower bound or the array is
+                always zero.
+                .
+                We have forked two repa modules: Shape and Index.
 
 Library
   Exposed-modules:
+    Data.Array.Repa.Index
+    Data.Array.Repa.Shape
+    Data.ExtShape
     Data.PrimitiveArray
-    Data.PrimitiveArray.Unboxed
+    Data.PrimitiveArray.Unboxed.Zero
   Build-depends:
     base >= 4 && <5,
     primitive >= 0.4,
-    vector >= 0.9,
-    repa >= 2.0
+    vector >= 0.9
   ghc-options:
     -Odph
     -funbox-strict-fields
+
 
 source-repository head
   type: git
