diff --git a/numhask-array.cabal b/numhask-array.cabal
--- a/numhask-array.cabal
+++ b/numhask-array.cabal
@@ -1,83 +1,77 @@
-name: numhask-array
-version: 0.0.2
-synopsis:
-  See readme.md
-description:
-  See readme.md for description.
-category:
-  project
-homepage:
-  https://github.com/tonyday567/numhask-array
-license:
-  BSD3
-license-file:
-  LICENSE
-author:
-  Tony Day
-maintainer:
-  tonyday567@gmail.com
-copyright:
-  Tony Day
-build-type:
-  Simple
-cabal-version:
-  >=1.14
-tested-with:
-  GHC == 8.0.1,
-  GHC == 8.2.1
+-- This file has been generated from package.yaml by hpack version 0.20.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: b12ab804325bfe4f740c04d520e84b39268daf23cbe7c9b2e14e7cb2ef52dcc8
+
+name:           numhask-array
+version:        0.1.0.0
+synopsis:       See readme.md
+description:    See readme.md for description.
+category:       project
+homepage:       https://github.com/tonyday567/numhask-array#readme
+bug-reports:    https://github.com/tonyday567/numhask-array/issues
+author:         Tony Day
+maintainer:     tonyday567@gmail.com
+copyright:      Tony Day
+license:        BSD3
+license-file:   LICENSE
+tested-with:    GHC==8.0.1 GHC==8.2.1 GHC==8.2.2
+build-type:     Simple
+cabal-version:  >= 1.10
+
 extra-source-files:
-  readme.md
-  stack.yaml
+    readme.md
+    stack.yaml
+
+source-repository head
+  type: git
+  location: https://github.com/tonyday567/numhask-array
+
 library
-  default-language:
-    Haskell2010
-  ghc-options:
-  hs-source-dirs:      
-    src
+  hs-source-dirs:
+      src
+  default-extensions: NegativeLiterals NoImplicitPrelude OverloadedStrings UnicodeSyntax
+  build-depends:
+      QuickCheck
+    , accelerate
+    , accelerate-llvm
+    , accelerate-llvm-native
+    , adjunctions >=4.0 && <5
+    , base >=4.7 && <5
+    , deepseq >=1.4.2.0 && <2
+    , dimensions
+    , distributive >=0.4 && <0.6
+    , ghc-typelits-natnormalise >=0.4 && <0.6
+    , numhask >=0.1.2 && <0.2
+    , protolude >=0.1 && <0.3
+    , singletons >=2.0 && <3
+    , typelits-witnesses >=0.2 && <0.3
+    , vector >=0.10 && <0.13
   exposed-modules:
-    NumHask.Array
-    NumHask.Array.Constraints
-    NumHask.Array.Example
+      NumHask.Accelerate
+      NumHask.Array
+      NumHask.Array.Constraints
+      NumHask.Array.Example
+      NumHask.Shape
   other-modules:
-
-  build-depends:
-    base >= 4.7 && < 5,
-    numhask >= 0.1.2 && < 0.2,
-    adjunctions >= 4.0 && < 5,
-    deepseq >= 1.4.2.0 && < 2,
-    distributive >= 0.4 && < 0.6,
-    ghc-typelits-natnormalise >= 0.4 && < 0.6,
-    protolude >= 0.1 && < 0.3,
-    singletons >= 2.0 && < 3,
-    typelits-witnesses >= 0.2 && < 0.3,
-    vector >= 0.10 && < 0.13
-  default-extensions:
-    NegativeLiterals,
-    NoImplicitPrelude,
-    OverloadedStrings,
-    UnicodeSyntax
+      Paths_numhask_array
+  default-language: Haskell2010
 
 test-suite test
-  default-language:
-    Haskell2010
-  type:
-    exitcode-stdio-1.0
+  type: exitcode-stdio-1.0
+  main-is: test.hs
   hs-source-dirs:
-    test
-  main-is:
-    test.hs
+      test
+  default-extensions: NegativeLiterals NoImplicitPrelude OverloadedStrings UnicodeSyntax
   build-depends:
-    base >= 4.7 && < 5,
-    doctest,
-    numhask >= 0.1.2 && < 0.2
-  default-extensions:
-    NegativeLiterals,
-    NoImplicitPrelude,
-    OverloadedStrings,
-    UnicodeSyntax
-
-source-repository head
-  type:
-    git
-  location:
-    https://github.com/tonyday567/numhask-array
+      QuickCheck
+    , base >=4.7 && <5
+    , doctest
+    , numhask >=0.1.2 && <0.2
+    , numhask-array
+    , tasty
+    , tasty-quickcheck
+  other-modules:
+      Paths_numhask_array
+  default-language: Haskell2010
diff --git a/readme.md b/readme.md
--- a/readme.md
+++ b/readme.md
@@ -5,13 +5,19 @@
 
 An experimental array with:
 
-- shape specified at the type level in n-dimensions
-- a [vector](https://www.stackage.org/package/vector) backend
+- a polymorphic container
+- shape specified at the type level
 - Representable instances
 - [numhask](https://www.stackage.org/package/numhask) heirarchy instances
 
 See [Examples](src/NumHask/Array/Example.hs) for the emergent API.
 
+Workflow
+---
 
+pkg_config hack courtesy of accelerate
 
+```
+PKG_CONFIG_PATH=/usr/local/opt/libFFI/lib/pkgconfig stack build --ghc-options -freverse-errors
+```
 
diff --git a/src/NumHask/Accelerate.hs b/src/NumHask/Accelerate.hs
new file mode 100644
--- /dev/null
+++ b/src/NumHask/Accelerate.hs
@@ -0,0 +1,248 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedLists #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS_GHC -Wall #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+-- | safe-typed n-dimensional arrays with Accelerate arrays under the hood
+module NumHask.Accelerate where
+
+import Data.Array.Accelerate.Array.Sugar (listToShape)
+import Data.Array.Accelerate.LLVM.Native (run)
+import Data.Singletons
+import Data.Singletons.TypeLits
+import GHC.Exts
+import GHC.Show
+import NumHask.Prelude hiding (All, Map)
+import NumHask.Shape
+import qualified Data.Array.Accelerate as A
+
+type family NatsToShape (ns :: [Nat]) where
+  NatsToShape '[] = A.Z
+  NatsToShape (x:xs) = NatsToShape xs A.:. Int
+
+-- $setup
+-- >>> :set -XDataKinds
+-- >>> :set -XOverloadedLists
+-- >>> :set -XTypeFamilies
+-- >>> let a = [1..24] :: ArrayAcc '[2,3,4] Int
+-- >>> let v = [1,2,3] :: ArrayAcc '[3] Int
+-- >>> a
+-- Array (Z :. 4 :. 3 :. 2) [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
+
+newtype ArrayAcc (r :: [Nat]) a = ArrayAcc (A.Acc (A.Array (NatsToShape r) a))
+
+instance forall (r :: [Nat]). (SingI r) => HasShape (ArrayAcc r) where
+  type Shape (ArrayAcc r) = [Int]
+  shape _ = fmap fromIntegral (fromSing (sing :: Sing r))
+
+instance
+    ( SingI r
+    , Num a
+    , A.Elt a
+    , A.Shape (NatsToShape r)
+    ) => IsList (ArrayAcc (r :: [Nat]) a) where
+  type Item (ArrayAcc r a) = a
+  fromList l = ArrayAcc $ A.use $ A.fromList (listToShape sh) l
+    where
+      sh = fmap fromIntegral (fromSing (sing :: Sing r))
+  toList (ArrayAcc a) = A.toList $ run a
+
+instance
+    ( Show a
+    , A.Elt a
+    , SingI r
+    , A.Shape (NatsToShape r)
+    ) => Show (ArrayAcc r a) where
+  show (ArrayAcc l) = GHC.Show.show $ run l
+
+instance
+    ( Eq a
+    , A.Elt a
+    , SingI r
+    , A.Shape (NatsToShape r)
+    , Eq (NatsToShape r)
+    ) => Eq (ArrayAcc r a) where
+  (==) (ArrayAcc a) (ArrayAcc b) = run a == run b
+
+bin :: (A.Elt a, A.Shape (NatsToShape r)) =>
+    (A.Exp a -> A.Exp a -> A.Exp a) -> ArrayAcc r a -> ArrayAcc r a -> ArrayAcc r a
+bin f (ArrayAcc a) (ArrayAcc b) = ArrayAcc (A.zipWith f a b)
+
+{-
+singleton ::
+    ( SingI r
+    , A.Elt a
+    , Num a
+    , A.Shape (NatsToShape r)
+    ) => [a] -> ArrayAcc (r :: [Nat]) a
+singleton a = ArrayAcc $ A.use $ A.fromList (listToShape sh) a
+    where
+      sh = fmap fromIntegral (fromSing (sing :: Sing r))
+-}
+
+-- Exp additive instances
+instance
+    ( A.Num a
+    , AdditiveMagma a) =>
+    AdditiveMagma (A.Exp a) where
+    plus = (A.+)
+
+instance
+    ( A.Num a
+    , AdditiveUnital a) =>
+    AdditiveUnital (A.Exp a) where
+    zero = A.constant zero
+
+instance
+    ( A.Num a
+    , AdditiveAssociative a) =>
+    AdditiveAssociative (A.Exp a)
+
+instance
+    ( A.Num a
+    , AdditiveCommutative a) =>
+    AdditiveCommutative (A.Exp a)
+
+instance
+    ( A.Num a
+    , Additive a) =>
+    Additive (A.Exp a)
+
+instance
+    ( A.Num a
+    , AdditiveInvertible a) =>
+    AdditiveInvertible (A.Exp a) where
+    negate = A.negate
+
+instance
+    ( A.Num a
+    , AdditiveGroup a) =>
+    AdditiveGroup (A.Exp a)
+
+-- Exp multiplivcative instances
+instance
+    ( A.Num a
+    , MultiplicativeMagma a) =>
+    MultiplicativeMagma (A.Exp a) where
+    times = (A.*)
+
+instance
+    ( A.Num a
+    , MultiplicativeUnital a) =>
+    MultiplicativeUnital (A.Exp a) where
+    one = A.constant one
+
+instance
+    ( A.Num a
+    , MultiplicativeAssociative a) =>
+    MultiplicativeAssociative (A.Exp a)
+
+instance
+    ( A.Num a
+    , MultiplicativeCommutative a) =>
+    MultiplicativeCommutative (A.Exp a)
+
+instance
+    ( A.Num a
+    , Multiplicative a) =>
+    Multiplicative (A.Exp a)
+
+instance
+    ( A.Num a
+    , Fractional (A.Exp a)
+    , MultiplicativeInvertible a) =>
+    MultiplicativeInvertible (A.Exp a) where
+    recip = A.recip
+
+instance
+    ( A.Num a
+    , Fractional (A.Exp a)
+    , MultiplicativeGroup a) =>
+    MultiplicativeGroup (A.Exp a)
+
+
+-- ArrayAcc additive instances
+instance
+    ( A.Shape (NatsToShape r)
+    , SingI r
+    , A.Num a
+    , AdditiveMagma a
+    ) =>
+    AdditiveMagma (ArrayAcc r a) where
+    plus = bin plus
+
+instance
+    ( A.Shape (NatsToShape r)
+    , SingI r
+    , A.Num a
+    , AdditiveUnital a
+    ) =>
+    AdditiveUnital (ArrayAcc r a) where
+    zero = ArrayAcc $ A.use (A.fromList (listToShape sh) (repeat zero))
+      where
+        sh = fmap fromIntegral (fromSing (sing :: Sing r))
+
+instance
+    ( A.Shape (NatsToShape r)
+    , SingI r
+    , A.Num a
+    , AdditiveAssociative a
+    ) =>
+    AdditiveAssociative (ArrayAcc r a)
+
+instance
+    ( A.Shape (NatsToShape r)
+    , SingI r
+    , A.Num a
+    , AdditiveCommutative a
+    ) =>
+    AdditiveCommutative (ArrayAcc r a)
+
+instance
+    ( A.Shape (NatsToShape r)
+    , SingI r
+    , A.Num a
+    , Additive a
+    ) =>
+    Additive (ArrayAcc r a)
+
+instance
+    ( A.Shape (NatsToShape r)
+    , SingI r
+    , A.Num a
+    , AdditiveInvertible a
+    ) =>
+    AdditiveInvertible (ArrayAcc r a) where
+    negate (ArrayAcc a) = ArrayAcc $ A.map A.negate a
+
+instance
+    ( A.Shape (NatsToShape r)
+    , SingI r
+    , A.Num a
+    , AdditiveGroup a
+    ) =>
+    AdditiveGroup (ArrayAcc r a)
+
+-- $additive tests
+-- >>> let m = [0..] :: ArrayAcc '[2,3] Int
+-- >>> m
+-- Array (Z :. 3 :. 2) [0,1,2,3,4,5]
+--
+-- >>> m+zero
+-- Array (Z :. 3 :. 2) [0,1,2,3,4,5]
+--
+-- >>> m+m
+-- Array (Z :. 3 :. 2) [0,2,4,6,8,10]
+--
+-- >>> m-m == zero
+-- True
+
+
+
+
diff --git a/src/NumHask/Array.hs b/src/NumHask/Array.hs
--- a/src/NumHask/Array.hs
+++ b/src/NumHask/Array.hs
@@ -1,71 +1,56 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE DataKinds #-}
-{-# LANGUAGE DeriveFoldable #-}
 {-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE OverloadedLists #-}
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeInType #-}
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
-{-# OPTIONS_GHC -Wall #-}
-{-# OPTIONS_GHC -fno-warn-type-defaults #-}
+-- you don't need this for ghc-8.2.2
+-- intero cracks about it though
+-- and doctest as well
+{-# LANGUAGE DatatypeContexts #-}
 
--- | safe-typed n-dimensional arrays
-module NumHask.Array
-  ( Array(..)
-  , SomeArray(..)
-  , row
-  , col
-  , unsafeRow
-  , unsafeCol
-  , slice
-  , unsafeSlice
-  , index
-  , unsafeIndex
-  , foldAlong
-  , mapAlong
-  , concatenate
-  , zipWith
-  , transpose
-  , squeeze
-  , (><)
-  , mmult
-  , fromList
-  ) where
+module NumHask.Array where
 
 import Data.Distributive
 import Data.Functor.Rep
+import Data.Kind
+import Data.List ((!!))
 import Data.Promotion.Prelude
 import Data.Singletons
-import Data.Singletons.Prelude
 import Data.Singletons.TypeLits
 import GHC.Exts
 import GHC.Show
-import GHC.Generics (Generic1)
--- import Control.DeepSeq (NFData1)
 import NumHask.Array.Constraints
-import NumHask.Prelude hiding (All, Map, (><), mmult, show, row, col, zipWith, transpose)
+import NumHask.Prelude as P
+import NumHask.Shape
+import Numeric.Dimensions
+import Numeric.Dimensions.Idx
+import Numeric.Dimensions.XDim
+
+import qualified Data.Singletons.Prelude as S
 import qualified Data.Vector as V
-import qualified NumHask.Prelude as P
-import Data.Kind
+import qualified Test.QuickCheck as QC
 
 -- $setup
 -- >>> :set -XDataKinds
 -- >>> :set -XOverloadedLists
 -- >>> :set -XTypeFamilies
--- >>> let a = [1..24] :: Array '[2,3,4] Int
--- >>> let v = [1,2,3] :: Array '[3] Int
+-- >>> let a = [1..24] :: Array [] '[2,3,4] Int
+-- >>> let v = [1,2,3] :: Array [] '[3] Int
 
--- | an n-dimensional array where shape is specified at the type level
--- The main purpose of this, beyond safe typing, is to supply the Representable instance with an initial object.
+-- | an array polymorphic in container and shape
 --
 -- >>> a
 -- [[[1, 2, 3, 4],
@@ -74,22 +59,91 @@
 --  [[13, 14, 15, 16],
 --   [17, 18, 19, 20],
 --   [21, 22, 23, 24]]]
-newtype Array (r :: [Nat]) a = Array (V.Vector a) deriving (Functor, Eq, Foldable, Generic, Generic1, NFData)
+data family Array (c :: Type -> Type) (ds :: [k]) (a :: Type)
 
--- | an n-dimensional array where shape is specified at the value level
-data SomeArray a =
-  SomeArray [Int]
-            (V.Vector a)
-  deriving (Functor, Eq, Foldable)
+-- | instance where dimensions are known at compile time
+newtype instance (Dimensions ds) =>
+  Array c ds t =
+    Array { _getContainer :: c t}
+    deriving (Functor, Foldable)
 
--- | convert a 'Array' to a 'SomeArray', losing the type level shape
-someArray :: (SingI r) => Array (r :: [Nat]) a -> SomeArray a
-someArray n@(Array v) = SomeArray (shape n) v
+-- | instance of array where some of the dimensions are known at compile time
+-- it wraps an Array with some weird magic
+data instance Array c (xds :: [XNat]) t = forall (ds :: [Nat]).
+  ( FixedDim xds ds ~ ds
+  , FixedXDim xds ds ~ xds
+  , Dimensions ds) =>
+  SomeArray (Array c ds t)
 
-instance forall (r :: [Nat]). (SingI r) => HasShape (Array r) where
-  type Shape (Array r) = [Int]
-  shape _ = fmap fromIntegral (fromSing (sing :: Sing r))
+-- | an array with dimensions represented at the value level
+newtype AnyArray c a = AnyArray ([Int], c a)
 
+-- | convert an array with type-level shape to value-level shape
+anyArray :: (Dimensions ds) => Array c ds a -> AnyArray c a
+anyArray arr@(Array c) = AnyArray (shape arr, c)
+
+-- | a sweet class of container with attributes necessary to supply the set of operations here
+class (Functor f) => Container f where
+  generate :: Int -> (Int -> a) -> f a
+  idx :: f a -> Int -> a
+  cslice :: Int -> Int -> f a -> f a
+  zipWith :: (a -> a -> a) -> f a -> f a -> f a
+    -- Chunks a container into a list of containers whose dimension are each i
+  chunkItUp :: [f a] -> Int -> f a -> [f a]
+  cfoldl' :: (b -> a -> b) -> b -> f a -> b
+  cfoldr :: (a -> b -> b) -> b -> f a -> b
+  cconcat :: [f a] -> f a
+
+instance Container V.Vector where
+  generate = V.generate
+  idx = V.unsafeIndex
+  cslice = V.unsafeSlice
+  zipWith = V.zipWith
+  chunkItUp acc i v =
+    if null v
+      then acc
+      else let (c, r) = V.splitAt i v
+           in chunkItUp (c : acc) i r
+  cfoldl' = V.foldl'
+  cfoldr = V.foldr
+  cconcat = V.concat
+
+instance Container [] where
+  generate n g = take n $ g <$> [0 ..]
+  idx = (!!)
+  cslice d t = take t . drop d
+  zipWith = P.zipWith
+  chunkItUp acc i v =
+    if null v
+      then acc
+      else let (c, r) = splitAt i v
+           in chunkItUp (c : acc) i r
+  cfoldl' = foldl'
+  cfoldr = foldr
+  cconcat = mconcat
+
+instance (Eq (c t), Dimensions ds) => Eq (Array c ds t) where
+    (Array a) == (Array b) = a == b
+
+xdimList :: XDim ds -> [Int]
+xdimList (XDim d) = dimList d
+
+dimList :: Dim ds -> [Int]
+dimList D = []
+dimList (d :* ds) = dimList d ++ dimList ds
+dimList (Dn :: Dim m) = [dimVal' @m]
+dimList (Dx (Dn :: Dim m)) = [dimVal' @m]
+
+instance (Dimensions r) => HasShape (Array c r) where
+  type Shape (Array c r) = [Int]
+  shape _ = dimList $ dim @r
+
+instance HasShape (Array c (xds :: [XNat])) where
+  type Shape (Array c xds) = [Int]
+  shape (SomeArray a) = shape a
+
+-- * shape helpers where dimensions ~ [Int]
+
 -- | convert from n-dim shape index to a flat index
 --
 -- >>> ind [2,3,4] [1,1,1]
@@ -111,60 +165,54 @@
     ([], x)
     ns
 
-instance forall r. (SingI r) => Distributive (Array r) where
-  distribute f =
-    Array $ V.generate n $ \i -> fmap (\(Array v) -> V.unsafeIndex v i) f
+instance forall r c. (Dimensions r, Container c) =>
+  Distributive (Array c r) where
+  distribute f = Array $ generate n $ \i -> fmap (\(Array v) -> idx v i) f
     where
-      n =
-        case (sing :: Sing r) of
-          SNil -> 1
-          (SCons x xs) -> product $ fromInteger <$> (fromSing x : fromSing xs)
+      n = dimVal $ dim @r
 
-instance forall (r :: [Nat]). (SingI r) => Representable (Array r) where
-  type Rep (Array r) = [Int]
-  tabulate f = Array $ V.generate (product ns) (f . unind ns)
+instance forall r c. (Dimensions r, Container c) =>
+  Representable (Array c r) where
+  type Rep (Array c r) = [Int]
+  tabulate f = Array $ generate (product ns) (f . unind ns)
     where
-      ns =
-        case (sing :: Sing r) of
-          SNil -> []
-          (SCons x xs) -> fromIntegral <$> (fromSing x : fromSing xs)
-  index (Array xs) rs = xs V.! ind ns rs
+      ns = dimList $ dim @r
+  index (Array xs) rs = xs `idx` ind ns rs
     where
-      ns =
-        case (sing :: Sing r) of
-          SNil -> []
-          (SCons x xs') -> fromIntegral <$> (fromSing x : fromSing xs')
+      ns = dimList $ dim @r
 
 -- | from flat list
-instance (SingI r, Num a) => IsList (Array (r :: [Nat]) a) where
-  type Item (Array r a) = a
-  fromList l = Array $ V.fromList $ take n $ l ++ repeat 0
+instance
+    ( Item (Array c r a) ~ Item (c a)
+    , Dimensions r
+    , AdditiveUnital a
+    , IsList (c a)
+    ) =>
+    IsList (Array c r a) where
+  type Item (Array c r a) = a
+  fromList l = Array $ fromList $ take n $ l ++ repeat zero
     where
-      n =
-        case (sing :: Sing r) of
-          SNil -> 1
-          (SCons x xs') ->
-            product $ fromIntegral <$> (fromSing x : fromSing xs')
-  toList (Array v) = V.toList v
+      n = dimVal (dim @r)
+  toList (Array v) = GHC.Exts.toList v
 
-instance (Show a) => Show (SomeArray a) where
-  show r@(SomeArray l _) = go (length l) r
+instance (Show a, Show (Item (c a)), Container c, IsList (c a)) => Show (AnyArray c a) where
+  show aa@(AnyArray (l,_)) = go (length l) aa
     where
-      go n r'@(SomeArray l' v') =
+      go n aa'@(AnyArray (l', c')) =
         case length l' of
-          0 -> show $ V.head v'
-          1 -> "[" ++ intercalate ", " (show <$> GHC.Exts.toList v') ++ "]"
+          0 -> "[]"
+          1 -> "[" ++ intercalate ", " (GHC.Show.show <$> GHC.Exts.toList c') ++ "]"
           x ->
             "[" ++
             intercalate
               (",\n" ++ replicate (n - x + 1) ' ')
-              (go n <$> flatten1 r') ++
+              (go n <$> flatten1 aa') ++
             "]"
 
 -- | convert the top layer of a SomeArray to a [SomeArray]
-flatten1 :: SomeArray a -> [SomeArray a]
-flatten1 (SomeArray rep v) =
-  (\s -> SomeArray (drop 1 rep) (V.unsafeSlice (s * l) l v)) <$> ss
+flatten1 :: (Container c) => AnyArray c a -> [AnyArray c a]
+flatten1 (AnyArray (rep, v)) =
+  (\s -> AnyArray (drop 1 rep, cslice (s * l) l v)) <$> ss
   where
     (n, l) =
       case rep of
@@ -172,87 +220,150 @@
         x:r -> (x, product r)
     ss = take n [0 ..]
 
-instance (Show a, SingI r) => Show (Array (r :: [Nat]) a) where
-  show = show . someArray
+instance (Show a, Show (Item (c a)), IsList (c a), Container c, Dimensions ds) => Show (Array c ds a) where
+  show = GHC.Show.show . anyArray
 
--- instance NFData (Array (r :: [Nat]) a) where
-    -- nrf (Array v) = Array (nrf v)
+type Vector c n = Array c '[ n]
 
+type Matrix c m n = Array c '[ m, n]
+
+instance
+  ( IsList (c a)
+  , Item (c a) ~ a
+  , KnownNat n
+  , AdditiveUnital (Vector c n a)
+  , QC.Arbitrary a
+  , AdditiveUnital a
+  , Num a
+  ) =>
+  QC.Arbitrary (Vector c n a) where
+  arbitrary = QC.frequency [(1, pure zero), (9, fromList <$> QC.vector n)]
+    where
+      n = fromInteger $ natVal (Proxy :: Proxy n)
+
+instance
+  ( IsList (c a)
+  , Item (c a) ~ a
+  , AdditiveUnital (Matrix c m n a)
+  , KnownNat m
+  , KnownNat n
+  , QC.Arbitrary a
+  , AdditiveUnital a
+  , Num a
+  ) =>
+  QC.Arbitrary (Matrix c m n a) where
+  arbitrary = QC.frequency [(1, pure zero), (9, fromList <$> QC.vector (m * n))]
+    where
+      n = fromInteger $ natVal (Proxy :: Proxy n)
+      m = fromInteger $ natVal (Proxy :: Proxy m)
+
+
 -- ** Operations
 -- | outer product
 --
 -- todo: reconcile with numhask version
 --
--- >>> v >< v
+-- >>> v NumHask.Array.>< v
 -- [[1, 2, 3],
 --  [2, 4, 6],
 --  [3, 6, 9]]
-(><) ::
-     forall (r :: [Nat]) (s :: [Nat]) a.
-     (CRing a, SingI r, SingI s, SingI (r :++ s))
-  => Array r a
-  -> Array s a
-  -> Array (r :++ s) a
+(><) :: forall c (r :: [Nat]) (s :: [Nat]) a.
+  ( Container c
+  , CRing a
+  , Dimensions r
+  , Dimensions s
+  , Dimensions (r ++ s))
+  => Array c r a
+  -> Array c s a
+  -> Array c (r ++ s) a
 (><) m n = tabulate (\i -> index m (take dimm i) * index n (drop dimm i))
   where
     dimm = length (shape m)
 
--- | matrix multiplication for a '2-Array'
+-- | matrix multiplication
 --
--- >>> let a = [1, 2, 3, 4] :: Array '[2, 2] Int
--- >>> let b = [5, 6, 7, 8] :: Array '[2, 2] Int
+-- >>> let a = [1, 2, 3, 4] :: Array [] '[2, 2] Int
+-- >>> let b = [5, 6, 7, 8] :: Array [] '[2, 2] Int
 -- >>> a
 -- [[1, 2],
 --  [3, 4]]
+--
 -- >>> b
 -- [[5, 6],
 --  [7, 8]]
+--
 -- >>> mmult a b
 -- [[19, 22],
 --  [43, 50]]
-mmult ::
-     forall m n k a.
-     (Semiring a, Num a, CRing a, KnownNat m, KnownNat n, KnownNat k)
-  => Array '[ m, k] a
-  -> Array '[ k, n] a
-  -> Array '[ m, n] a
+--
+mmult :: forall c m n k a.
+  ( Hilbert (Vector c k) a
+  , Dimensions '[ m, k]
+  , Dimensions '[ k, n]
+  , Dimensions '[ m, n]
+  , Container c
+  , Semiring a
+  , Num a
+  , CRing a
+  , KnownNat m
+  , KnownNat n
+  , KnownNat k
+  )
+  => Matrix c m k a
+  -> Matrix c k n a
+  -> Matrix c m n a
 mmult x y = tabulate (\[i, j] -> unsafeRow i x <.> unsafeCol j y)
 
 -- | extract the row of a matrix
-row ::
-     forall i a m n. (KnownNat m, KnownNat n, KnownNat i, (i :< m) ~ 'True)
+row :: forall c i a m n.
+  ( Dimensions '[ m, n]
+  , Container c
+  , KnownNat m
+  , KnownNat n
+  , KnownNat i
+  , (i S.:< m) ~ 'True
+  )
   => Proxy i
-  -> Array '[ m, n] a
-  -> Array '[ n] a
+  -> Matrix c m n a
+  -> Vector c n a
 row i_ = unsafeRow i
   where
-    i = (fromIntegral . fromSing . singByProxy) i_
+    i = (fromIntegral . S.fromSing . S.singByProxy) i_
 
-unsafeRow ::
-     forall a m n. (KnownNat m, KnownNat n)
+unsafeRow :: forall c a m n.
+  ( Container c
+  , KnownNat m
+  , KnownNat n
+  , Dimensions '[ m, n])
   => Int
-  -> Array '[ m, n] a
-  -> Array '[ n] a
-unsafeRow i t@(Array a) = Array $ V.unsafeSlice (i * n) n a
+  -> Matrix c m n a
+  -> Vector c n a
+unsafeRow i t@(Array a) = Array $ cslice (i * n) n a
   where
     [_, n] = shape t
 
 -- | extract the column of a matrix
-col ::
-     forall j a m n. (KnownNat m, KnownNat n, KnownNat j, (j :< n) ~ 'True)
+col :: forall c j a m n.
+  ( Dimensions '[ m, n]
+  , Container c
+  , KnownNat m
+  , KnownNat n
+  , KnownNat j
+  , (j S.:< n) ~ 'True
+  )
   => Proxy j
-  -> Array '[ m, n] a
-  -> Array '[ m] a
+  -> Matrix c m n a
+  -> Vector c m a
 col j_ = unsafeCol j
   where
-    j = (fromIntegral . fromSing . singByProxy) j_
+    j = (fromIntegral . S.fromSing . S.singByProxy) j_
 
 unsafeCol ::
-     forall a m n. (KnownNat m, KnownNat n)
+     forall c a m n. (Container c, KnownNat m, KnownNat n, Dimensions '[ m, n])
   => Int
-  -> Array '[ m, n] a
-  -> Array '[ m] a
-unsafeCol j t@(Array a) = Array $ V.generate m (\x -> a V.! (j + x * n))
+  -> Matrix c m n a
+  -> Vector c m a
+unsafeCol j t@(Array a) = Array $ generate m (\x -> a `idx` (j + x * n))
   where
     [m, n] = shape t
 
@@ -260,80 +371,93 @@
 --
 -- >>> unsafeIndex a [0,2,1]
 -- 10
-unsafeIndex :: SingI r => Array r a -> [Int] -> a
-unsafeIndex t@(Array a) i = a V.! ind (shape t) i
+unsafeIndex :: (Container c, Dimensions r) => Array c r a -> [Int] -> a
+unsafeIndex t@(Array a) i = a `idx` ind (shape t) i
 
 -- |
 --
--- >>> unsafeSlice [[0,1],[2],[1,2]] a :: Array '[2,1,2] Int
+-- >>> unsafeSlice [[0,1],[2],[1,2]] a :: Array [] '[2,1,2] Int
 -- [[[10, 11]],
 --  [[22, 23]]]
-unsafeSlice :: (SingI r) => [[Int]] -> Array r a -> Array r0 a
-unsafeSlice s t = Array (V.fromList [unsafeIndex t i | i <- sequence s])
+unsafeSlice ::
+     (Container c, IsList (c a), Item (c a) ~ a, Dimensions r, Dimensions r0)
+  => [[Int]]
+  -> Array c r a
+  -> Array c r0 a
+unsafeSlice s t = Array (fromList [unsafeIndex t i | i <- sequence s])
 
 -- | Slice xs = Map Length xs
 type family Slice (xss :: [[Nat]]) :: [Nat] where
-  Slice xss = Map LengthSym0 xss
+  Slice xss = Data.Promotion.Prelude.Map LengthSym0 xss
 
 -- | AllLT xs n = All (n >) xs
-data AllLTSym0 (a :: TyFun [Nat] (TyFun Nat Bool -> Type))
+data AllLTSym0 (a :: S.TyFun [Nat] (S.TyFun Nat Bool -> Type))
 
-data AllLTSym1 (l :: [Nat]) (a :: TyFun Nat Bool)
+data AllLTSym1 (l :: [Nat]) (a :: S.TyFun Nat Bool)
 
-type instance Apply AllLTSym0 l = AllLTSym1 l
+type instance S.Apply AllLTSym0 l = AllLTSym1 l
 
-type instance Apply (AllLTSym1 l) n = All ((:>$$) n) l
+type instance S.Apply (AllLTSym1 l) n =
+     Data.Promotion.Prelude.All ((S.:>$$) n) l
 
 -- |
 --
--- >>> slice (Proxy :: Proxy '[ '[0,1],'[2],'[1,2]]) a
+-- todo: an ambiguous type variable has snucjk in here somewhere
+--
+-- > slice (Proxy :: Proxy '[ '[0,1],'[2],'[1,2]]) a
 -- [[[10, 11]],
 --  [[22, 23]]]
+{-
+todo:
+    • Expected kind ‘[[Nat]]’, but ‘s’ has kind ‘[Nat]’
+    • In the first argument of ‘Slice’, namely ‘s’
+      In the first argument of ‘Array’, namely ‘(Slice s)’
+      In the type signature:
+        slice :: forall c s r a.
+                 (Container c,
+                  Dimensions s,
+                  Dimensions r,
+                  And (ZipWith AllLTSym0 s r) ~  'True) =>
+                 Proxy s -> Array c r a -> Array (Slice s) c a
+-}
+{-
 slice ::
-     forall s r a. (SingI s, SingI r, And (ZipWith AllLTSym0 s r) ~ 'True)
+     forall c s r a. (Container c, Dimensions s, Dimensions r, S.And (S.ZipWith AllLTSym0 s r) ~ 'True)
   => Proxy s
-  -> Array r a
-  -> Array (Slice s) a
+  -> Array c r a
+  -> Array (Slice s) c a
+-}
 slice s_ = unsafeSlice s
   where
     s = ((fmap . fmap) fromInteger . fromSing . singByProxy) s_
 
--- Chunks a vector v into a list of modules whose dimension is each i
-chunkItUp :: [V.Vector a] -> Int -> V.Vector a -> [V.Vector a]
-chunkItUp acc i v =
-  if null v
-    then acc
-    else let (c, r) = V.splitAt i v
-         in chunkItUp (c : acc) i r
-
-zipWith :: (a -> a -> a) -> Array s a -> Array s a -> Array s a
-zipWith fn (Array a) (Array b) = Array $ V.zipWith fn a b
-
 -- |
 --
--- >>> foldAlong (Proxy :: Proxy 1) (\_ -> ([0..3] :: Array '[4] Int)) a
+-- >>> foldAlong (Proxy :: Proxy 1) (\_ -> ([0..3] :: Array [] '[4] Int)) a
 -- [[0, 1, 2, 3],
 --  [0, 1, 2, 3]]
 --
 -- todo: resolution of a primitive and a scalar eg
 --        Expected type: Array '[10] Int -> Array '[] Int
 --        Actual type: Array '[10] (Array '[] Int) -> Array '[] Int
+--
 foldAlong ::
-     forall s vw uvw uw w a.
-     ( SingI s
-     , SingI uvw
+     forall c s vw uvw uw w a.
+     ( Container c
+     , KnownNat s
+     , Dimensions uvw
      , uw ~ (Fold s uvw)
-     , w ~ (Drop 1 vw)
+     , w ~ (Data.Promotion.Prelude.Drop 1 vw)
      , vw ~ (TailModule s uvw)
      )
   => Proxy s
-  -> (Array vw a -> Array w a)
-  -> Array uvw a
-  -> Array uw a
+  -> (Array c vw a -> Array c w a)
+  -> Array c uvw a
+  -> Array c uw a
 foldAlong s_ f a@(Array v) =
   Array $
-  V.concat
-    (foldl'
+  cconcat
+    (cfoldl'
        (\xs x ->
           let (Array vx) = f (Array x)
           in vx : xs)
@@ -345,23 +469,27 @@
 
 -- |
 --
--- >>> mapAlong (Proxy :: Proxy 0) (\x -> NumHask.Array.zipWith (*) x x) a
+-- todo: No instance for (Container (Array [] '[]) error
+--
+-- > mapAlong (Proxy :: Proxy 0) (\x -> NumHask.Array.zipWith (*) x x) a
 -- [[[1, 4, 9, 16],
 --   [25, 36, 49, 64],
 --   [81, 100, 121, 144]],
 --  [[169, 196, 225, 256],
 --   [289, 324, 361, 400],
 --   [441, 484, 529, 576]]]
+--
 mapAlong ::
-     forall s uvw vw a. (SingI s, SingI uvw, vw ~ (HeadModule s uvw))
+     forall c s uvw vw a.
+     (Container c, KnownNat s, Dimensions uvw, vw ~ (HeadModule s uvw))
   => Proxy s
-  -> (Array vw a -> Array vw a)
-  -> Array uvw a
-  -> Array uvw a
+  -> (Array c vw a -> Array c vw a)
+  -> Array c uvw a
+  -> Array c uvw a
 mapAlong s_ f a@(Array v) =
   Array $
-  V.concat
-    (foldl'
+  cconcat
+    (cfoldl'
        (\xs x ->
           let (Array vx) = f (Array x)
           in vx : xs)
@@ -380,14 +508,21 @@
 --  [[13, 14, 15, 16, 13, 14, 15, 16],
 --   [17, 18, 19, 20, 17, 18, 19, 20],
 --   [21, 22, 23, 24, 21, 22, 23, 24]]]
+--
 concatenate ::
-     forall s r t a. (SingI s, SingI r, SingI t, (IsValidConcat s t r) ~ 'True)
+     forall c s r t a.
+     ( Container c
+     , SingI s
+     , Dimensions r
+     , Dimensions t
+     , (IsValidConcat s t r) ~ 'True
+     )
   => Proxy s
-  -> Array r a
-  -> Array t a
-  -> Array (Concatenate s t r) a
+  -> Array c r a
+  -> Array c t a
+  -> Array c (Concatenate s t r) a
 concatenate s_ r@(Array vr) t@(Array vt) =
-  Array . V.concat $ (concat . reverse . P.transpose) [rm, tm]
+  Array . cconcat $ (concat . reverse . P.transpose) [rm, tm]
   where
     s = (fromInteger . fromSing . singByProxy) s_
     rm = chunkItUp [] (product $ drop s $ shape t) vt
@@ -408,15 +543,17 @@
 --  [[19, 20],
 --   [21, 22],
 --   [23, 24]]]
+--
 transpose ::
-     forall s t a. (t ~ Transpose s)
-  => Array s a
-  -> Array t a
+     forall c s t a. (t ~ Transpose s, Container c, Dimensions s, Dimensions t)
+  => Array c s a
+  -> Array c t a
 transpose (Array x) = Array x
 
+
 -- |
 --
--- >>> let a = [1..24] :: Array '[2,1,3,4,1] Int
+-- >>> let a = [1..24] :: Array [] '[2,1,3,4,1] Int
 -- >>> a
 -- [[[[[1],
 --     [2],
@@ -449,92 +586,153 @@
 --  [[13, 14, 15, 16],
 --   [17, 18, 19, 20],
 --   [21, 22, 23, 24]]]
+--
 squeeze ::
-     forall s t a. (t ~ Squeeze s)
-  => Array s a
-  -> Array t a
+     forall c s t a. (t ~ Squeeze s)
+  => Array c s a
+  -> Array c t a
 squeeze (Array x) = Array x
 
-instance (SingI r, AdditiveMagma a) => AdditiveMagma (Array r a) where
+instance (Dimensions r, Container c, AdditiveMagma a) =>
+         AdditiveMagma (Array c r a) where
   plus = liftR2 plus
 
-instance (SingI r, AdditiveUnital a) => AdditiveUnital (Array r a) where
+instance (Dimensions r, Container c, AdditiveUnital a) =>
+         AdditiveUnital (Array c r a) where
   zero = pureRep zero
 
-instance (SingI r, AdditiveAssociative a) =>
-         AdditiveAssociative (Array r a)
+instance (Dimensions r, Container c, AdditiveAssociative a) =>
+         AdditiveAssociative (Array c r a)
 
-instance (SingI r, AdditiveCommutative a) =>
-         AdditiveCommutative (Array r a)
+instance (Dimensions r, Container c, AdditiveCommutative a) =>
+         AdditiveCommutative (Array c r a)
 
-instance (SingI r, AdditiveInvertible a) => AdditiveInvertible (Array r a) where
+instance (Dimensions r, Container c, AdditiveInvertible a) =>
+         AdditiveInvertible (Array c r a) where
   negate = fmapRep negate
 
-instance (SingI r, Additive a) => Additive (Array r a)
+instance (Dimensions r, Container c, Additive a) => Additive (Array c r a)
 
-instance (SingI r, AdditiveGroup a) => AdditiveGroup (Array r a)
+instance (Dimensions r, Container c, AdditiveGroup a) =>
+         AdditiveGroup (Array c r a)
 
-instance (SingI r, MultiplicativeMagma a) =>
-         MultiplicativeMagma (Array r a) where
+instance (Dimensions r, Container c, MultiplicativeMagma a) =>
+         MultiplicativeMagma (Array c r a) where
   times = liftR2 times
 
-instance (SingI r, MultiplicativeUnital a) =>
-         MultiplicativeUnital (Array r a) where
+instance (Dimensions r, Container c, MultiplicativeUnital a) =>
+         MultiplicativeUnital (Array c r a) where
   one = pureRep one
 
-instance (SingI r, MultiplicativeAssociative a) =>
-         MultiplicativeAssociative (Array r a)
+instance (Dimensions r, Container c, MultiplicativeAssociative a) =>
+         MultiplicativeAssociative (Array c r a)
 
-instance (SingI r, MultiplicativeCommutative a) =>
-         MultiplicativeCommutative (Array r a)
+instance (Dimensions r, Container c, MultiplicativeCommutative a) =>
+         MultiplicativeCommutative (Array c r a)
 
-instance (SingI r, MultiplicativeInvertible a) =>
-         MultiplicativeInvertible (Array r a) where
+instance (Dimensions r, Container c, MultiplicativeInvertible a) =>
+         MultiplicativeInvertible (Array c r a) where
   recip = fmapRep recip
 
-instance (SingI r, Multiplicative a) => Multiplicative (Array r a)
+instance (Dimensions r, Container c, Multiplicative a) =>
+         Multiplicative (Array c r a)
 
-instance (SingI r, MultiplicativeGroup a) =>
-         MultiplicativeGroup (Array r a)
+instance (Dimensions r, Container c, MultiplicativeGroup a) =>
+         MultiplicativeGroup (Array c r a)
 
-instance (SingI r, MultiplicativeMagma a, Additive a) =>
-         Distribution (Array r a)
+instance (Dimensions r, Container c, MultiplicativeMagma a, Additive a) =>
+         Distribution (Array c r a)
 
-instance (SingI r, Semiring a) => Semiring (Array r a)
+instance (Dimensions r, Container c, Semiring a) => Semiring (Array c r a)
 
-instance (SingI r, Ring a) => Ring (Array r a)
+instance (Dimensions r, Container c, Ring a) => Ring (Array c r a)
 
-instance (SingI r, CRing a) => CRing (Array r a)
+instance (Dimensions r, Container c, CRing a) => CRing (Array c r a)
 
-instance (SingI r, Field a) => Field (Array r a)
+instance (Dimensions r, Container c, Field a) => Field (Array c r a)
 
-instance (SingI r, ExpField a) => ExpField (Array r a) where
+instance (Dimensions r, Container c, ExpField a) => ExpField (Array c r a) where
   exp = fmapRep exp
   log = fmapRep log
 
-instance (SingI r, BoundedField a) => BoundedField (Array r a) where
+instance (Foldable (Array c r), Dimensions r, Container c, BoundedField a) =>
+         BoundedField (Array c r a) where
   isNaN f = or (fmapRep isNaN f)
 
-instance (SingI r, Signed a) => Signed (Array r a) where
+instance (Dimensions r, Container c, Signed a) => Signed (Array c r a) where
   sign = fmapRep sign
   abs = fmapRep abs
 
-instance (ExpField a) => Normed (Array r a) a where
+instance (Functor (Array c r), Foldable (Array c r), ExpField a) =>
+         Normed (Array c r a) a where
   size r = sqrt $ foldr (+) zero $ (** (one + one)) <$> r
 
-instance (SingI r, Epsilon a) => Epsilon (Array r a) where
+instance (Foldable (Array c r), Dimensions r, Container c, Epsilon a) =>
+         Epsilon (Array c r a) where
   nearZero f = and (fmapRep nearZero f)
   aboutEqual a b = and (liftR2 aboutEqual a b)
 
-instance (SingI r, ExpField a) => Metric (Array r a) a where
+instance (Foldable (Array c r), Dimensions r, Container c, ExpField a) =>
+         Metric (Array c r a) a where
   distance a b = size (a - b)
 
-instance (SingI r, Integral a) => Integral (Array r a) where
+instance (Dimensions r, Container c, Integral a) => Integral (Array c r a) where
   divMod a b = (d, m)
     where
       x = liftR2 divMod a b
       d = fmap fst x
       m = fmap snd x
 
-instance (CRing a, Num a, Semiring a, SingI r) => Hilbert (Array r) a where
+instance (Foldable (Array c r), CRing a, Semiring a, Dimensions r, Container c) =>
+         Hilbert (Array c r) a where
   a <.> b = sum $ liftR2 (*) a b
+
+instance (Dimensions r, Container c, Additive a) =>
+         AdditiveBasis (Array c r) a where
+  (.+.) = liftR2 (+)
+
+instance (Dimensions r, Container c, AdditiveGroup a) =>
+         AdditiveGroupBasis (Array c r) a where
+  (.-.) = liftR2 (-)
+
+instance (Dimensions r, Container c, Multiplicative a) =>
+         MultiplicativeBasis (Array c r) a where
+  (.*.) = liftR2 (*)
+
+instance (Dimensions r, Container c, MultiplicativeGroup a) =>
+         MultiplicativeGroupBasis (Array c r) a where
+  (./.) = liftR2 (/)
+
+instance (Dimensions r, Container c, Additive a) =>
+         AdditiveModule (Array c r) a where
+  (.+) r s = fmap (s +) r
+  (+.) s = fmap (s +)
+
+instance (Dimensions r, Container c, AdditiveGroup a) =>
+         AdditiveGroupModule (Array c r) a where
+  (.-) r s = fmap (\x -> x - s) r
+  (-.) s = fmap (\x -> x - s)
+
+instance (Dimensions r, Container c, Multiplicative a) =>
+         MultiplicativeModule (Array c r) a where
+  (.*) r s = fmap (s *) r
+  (*.) s = fmap (s *)
+
+instance (Dimensions r, Container c, MultiplicativeGroup a) =>
+         MultiplicativeGroupModule (Array c r) a where
+  (./) r s = fmap (/ s) r
+  (/.) s = fmap (/ s)
+
+instance (Dimensions r, Container c) => Singleton (Array c r) where
+  singleton = pureRep
+
+instance ( Foldable (Array c r)
+         , Dimensions r
+         , Container c
+         , CRing a
+         , Multiplicative a
+         ) =>
+         TensorProduct (Array c r a) where
+  (><) m n = tabulate (\i -> index m i *. n)
+  timesleft v m = tabulate (\i -> v <.> index m i)
+  timesright m v = tabulate (\i -> v <.> index m i)
diff --git a/src/NumHask/Array/Example.hs b/src/NumHask/Array/Example.hs
--- a/src/NumHask/Array/Example.hs
+++ b/src/NumHask/Array/Example.hs
@@ -40,6 +40,7 @@
   ) where
 
 import NumHask.Array as A
+import NumHask.Shape
 import NumHask.Prelude as P
 
 -- $setup
@@ -49,17 +50,14 @@
 -- >>> :set -XFlexibleContexts
 -- >>> import NumHask.Array as A
 -- >>> import GHC.Exts (fromList)
--- >>> -- import NumHask.Space hiding (singleton)
--- >>> -- import NumHask.Range
--- >>> import qualified Data.Vector as V
 
 -- $anExample
 -- construction can be lazy; and zero pads
 --
--- >>> let z = [] :: Array '[2] Int
+-- >>> let z = [] :: Array [] '[2] Int
 -- >>> z
 -- [0, 0]
--- >>> let a = [0..] :: Array '[3,5] Int
+-- >>> let a = [0..] :: Array [] '[3,5] Int
 -- >>> a
 -- [[0, 1, 2, 3, 4],
 --  [5, 6, 7, 8, 9],
@@ -69,41 +67,41 @@
 -- >>> length (shape a) -- dimension
 -- 2
 -- >>> :t a
--- a :: Array '[3, 5] Int
+-- a :: Array [] '[3, 5] Int
 -- >>> import qualified Data.Vector as V
 -- >>> let v = V.fromList [6,7,8]
 -- >>> :t v
 -- v :: Num a => V.Vector a
 -- >>> let b = Array v
 -- >>> :t b
--- b :: Num a => Array r a
--- >>> b :: Array '[3] Int
+-- b :: Num t => Array V.Vector ds t
+-- >>> b :: Array V.Vector '[3] Int
 -- [6, 7, 8]
 
 -- $arrayCreation
 --
 -- >>> -- fixed size arrays are fully shape specified at the type level
--- >>> let a = [2, 3, 4] :: Array '[3] Int
+-- >>> let a = [2, 3, 4] :: Array [] '[3] Int
 -- >>> a
 -- [2, 3, 4]
--- >>> [1.2, 3.5, 5.1] :: Array '[3] Double
+-- >>> [1.2, 3.5, 5.1] :: Array [] '[3] Double
 -- [1.2, 3.5, 5.1]
 --
 -- >>> -- lists of lists is not a thing, and need to be flattened
 -- >>> let ls = [[1.0,2.0,3.0],[4.0,5.0,6.0]] :: [[Double]]
--- >>> fromList (concat ls) :: Array '[2,3] Double
+-- >>> fromList (concat ls) :: Array [] '[2,3] Double
 -- [[1.0, 2.0, 3.0],
 --  [4.0, 5.0, 6.0]]
 --
--- >>> fromList ((\x -> (fromIntegral x) :+ zero) <$> [1,2,3,4]) :: Array '[2,2] (Complex Double)
+-- >>> fromList ((\x -> (fromIntegral x) :+ zero) <$> [1,2,3,4]) :: Array [] '[2,2] (Complex Double)
 -- [[1.0 :+ 0.0, 2.0 :+ 0.0],
 --  [3.0 :+ 0.0, 4.0 :+ 0.0]]
--- >>> let z = [] :: Array '[3,4] Int
+-- >>> let z = [] :: Array [] '[3,4] Int
 -- >>> z
 -- [[0, 0, 0, 0],
 --  [0, 0, 0, 0],
 --  [0, 0, 0, 0]]
--- >>> let o = singleton one :: Array '[2,3,4] Int
+-- >>> let o = singleton one :: Array [] '[2,3,4] Int
 -- >>> o
 -- [[[1, 1, 1, 1],
 --   [1, 1, 1, 1],
@@ -111,30 +109,30 @@
 --  [[1, 1, 1, 1],
 --   [1, 1, 1, 1],
 --   [1, 1, 1, 1]]]
--- >>> let empt = singleton nan :: Array '[2,3] Double
+-- >>> let empt = singleton nan :: Array [] '[2,3] Double
 -- >>> empt
 -- [[NaN, NaN, NaN],
 --  [NaN, NaN, NaN]]
 --
--- >>>  [10,15 .. 30] :: Array '[4] Int
+-- >>>  [10,15 .. 30] :: Array [] '[4] Int
 -- [10, 15, 20, 25]
--- >>> [0, 0.3.. 2] :: Array '[7] Double
+-- >>> [0, 0.3.. 2] :: Array [] '[7] Double
 -- [0.0, 0.3, 0.6, 0.8999999999999999, 1.1999999999999997, 1.4999999999999996, 1.7999999999999994]
 --
 -- > todo: fix NumHask.Range grid
--- > fromList (grid OuterPos (Range 0 2) 8) :: Array '[9] Double
+-- > fromList (grid OuterPos (Range 0 2) 8) :: Array [] '[9] Double
 -- > [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0]
--- > let x = fromList (grid OuterPos (Range 0 (2*pi)) 100) :: Array '[101] Double
+-- > let x = fromList (grid OuterPos (Range 0 (2*pi)) 100) :: Array [] '[101] Double
 -- > let f = fmap sin x
 --
 
 -- $printingArrays
--- >>> show ([0..] :: Array '[6] Int) :: Text
+-- >>> show ([0..] :: Array [] '[6] Int) :: Text
 -- "[0, 1, 2, 3, 4, 5]"
--- >>> [0..] :: Array '[2,3] Int
+-- >>> [0..] :: Array [] '[2,3] Int
 -- [[0, 1, 2],
 --  [3, 4, 5]]
--- >>> [0..] :: Array '[1,2,3,1] Int
+-- >>> [0..] :: Array [] '[1,2,3,1] Int
 -- [[[[0],
 --    [1],
 --    [2]],
@@ -144,7 +142,7 @@
 --
 -- > todo: implement display
 -- > import Formatting
--- > display (left 7 . fixed 2) ", " (fromList $ fromIntegral <$> [0..] :: Array '[100,100] Double)
+-- > display (left 7 . fixed 2) ", " (fromList $ fromIntegral <$> [0..] :: Array [] '[100,100] Double)
 -- > [[   0.00,    1.00,    2.00 ..   98.00   99.00],
 -- >  [ 100.00,  101.00,  102.00 ..  198.00  199.00],
 -- >  [ 200.00,  201.00,  202.00 ..  298.00  299.00],
@@ -155,21 +153,21 @@
 
 -- $basicOperation
 --
--- >>> let a = [20,30,40,50] :: Array '[4] Double
--- >>> let b = [0..] :: Array '[4] Double
+-- >>> let a = [20,30,40,50] :: Array [] '[4] Double
+-- >>> let b = [0..] :: Array [] '[4] Double
 -- >>> let c = a - b
 -- >>> c
 -- [20.0, 29.0, 38.0, 47.0]
 -- >>> -- todo: resolve potential to polymorph number literals eg b**2
 -- >>> b ** (one+one)
 -- [0.0, 1.0, 4.0, 9.000000000000002]
--- >>> 10 *. sin <$> a
+-- >>> 10 *. (sin <$> a)
 -- [9.129452507276277, -9.880316240928618, 7.451131604793488, -2.6237485370392877]
 -- >>> (<35) <$> a
 -- [True, True, False, False]
 --
--- >>> let a = [0..] :: Array '[2,3] Int
--- >>> let b = [0..] :: Array '[3,2] Int
+-- >>> let a = [0..] :: Array [] '[2,3] Int
+-- >>> let b = [0..] :: Array [] '[3,2] Int
 -- >>> a .*. a
 -- [[0, 1, 4],
 --  [9, 16, 25]]
@@ -184,17 +182,17 @@
 -- >>> -- random example skipped
 --
 -- > -- todo: awaiting grid fix
--- > let a = singleton one :: Array '[3] Double
--- > let b = fromList (grid OuterPos (Range 0 pi) 2) :: Array '[3] Double
+-- > let a = singleton one :: Array [] '[3] Double
+-- > let b = fromList (grid OuterPos (Range 0 pi) 2) :: Array [] '[3] Double
 -- > let c = a + b
 -- > let d = exp . ((zero:+one) *.) $ (:+zero) <$> c
 -- > d
 -- [0.5403023058681398 :+ 0.8414709848078965, (-0.8414709848078965) :+ 0.5403023058681398, (-0.5403023058681399) :+ (-0.8414709848078964)]
 -- > :t d
--- d :: Array '[3] (Complex Double)
+-- d :: Array [] '[3] (Complex Double)
 --
 -- >>> -- folding
--- >>> let a = [0..] :: Array '[2,5] Int
+-- >>> let a = [0..] :: Array [] '[2,5] Int
 -- >>> sum a
 -- 45
 -- >>> minimum a
@@ -206,7 +204,7 @@
 
 -- $universalFunctions
 --
--- >>> let a = [0..] :: Array '[3] Double
+-- >>> let a = [0..] :: Array [] '[3] Double
 -- >>> exp <$> a
 -- [1.0, 2.718281828459045, 7.38905609893065]
 -- >>> sqrt <$> a
@@ -215,21 +213,21 @@
 
 -- $indexingSlicingIterating
 --
--- >>> let a = (\x -> x*x*x) <$> [0..] :: Array '[10] Int
+-- >>> let a = (\x -> x*x*x) <$> [0..] :: Array [] '[10] Int
 -- >>> index a [2]
 -- 8
--- >>> let s = (\i -> index a [i]) <$> [2..5] :: Array '[4] Int
+-- >>> let s = (\i -> index a [i]) <$> [2..5] :: Array [] '[4] Int
 -- >>> s
 -- [8, 27, 64, 125]
 -- >>> :t s
--- s :: Array '[4] Int
+-- s :: Array [] '[4] Int
 -- >>> -- replace every second number with -1000
--- >>> let a' = (tabulate (\[i] -> if i `mod` 2 == 0 then -1000 else (index a [i]))) :: Array '[10] Int
+-- >>> let a' = (tabulate (\[i] -> if i `mod` 2 == 0 then -1000 else (index a [i]))) :: Array [] '[10] Int
 -- >>> a'
 -- [-1000, 1, -1000, 27, -1000, 125, -1000, 343, -1000, 729]
 --
 -- > -- todo: reverse fix
--- > let a'' = (let (n:_) = shape a in tabulate (\[i] -> index a [n-i])) :: Array '[4] Int
+-- > let a'' = (let (n:_) = shape a in tabulate (\[i] -> index a [n-i])) :: Array [] '[4] Int
 -- > a''
 -- > [729, -1000, 343, -1000, 125, -1000, 27, -1000, 1, -1000]
 --
diff --git a/src/NumHask/Shape.hs b/src/NumHask/Shape.hs
new file mode 100644
--- /dev/null
+++ b/src/NumHask/Shape.hs
@@ -0,0 +1,21 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS_GHC -Wall #-}
+
+-- | numbers with a shape
+module NumHask.Shape
+  ( HasShape(..)
+    -- * Representable
+    -- | Representable has most of what's needed to define numbers that have elements (aka scalars) and a fixed shape.
+  , Representable(..)
+  ) where
+
+import Data.Functor.Rep
+
+-- | Not everything that has a shape is representable.
+--
+-- todo: Structure is a useful alternative concept/naming convention
+class HasShape f where
+  type Shape f
+  shape :: f a -> Shape f
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,9 +1,10 @@
-resolver: lts-9.3
+resolver: nightly-2018-01-18
 
 packages:
   - '.'
 
 extra-deps:
-  - numhask-0.1.2
-  # - deepseq-1.4.3.0
+  #- numhask-0.1.3
+  - dimensions-0.3.2.0
+  # - deepseq-1.4.3.0i
 
diff --git a/test/test.hs b/test/test.hs
--- a/test/test.hs
+++ b/test/test.hs
@@ -1,9 +1,16 @@
+{-# LANGUAGE DataKinds #-}
 {-# OPTIONS_GHC -Wall #-}
 
 module Main where
 
 import NumHask.Prelude
+import NumHask.Laws
+import NumHask.Array
+
 import Test.DocTest
+import Test.Tasty
+       (TestTree, defaultMain, testGroup, localOption)
+import Test.Tasty.QuickCheck
 
 main :: IO ()
 main = do
@@ -11,3 +18,103 @@
   doctest ["src/NumHask/Array.hs"]
   putStrLn ("Example DocTest" :: Text)
   doctest ["src/NumHask/Array/Example.hs"]
+  putStrLn ("ArrayAcc DocTest" :: Text)
+  doctest ["src/NumHask/Accelerate.hs"]
+  defaultMain tests
+
+tests :: TestTree
+tests =
+  testGroup
+    "NumHask"
+    [ testsVInt
+    , testsMInt
+    , testsVFloat
+    , testsMFloat
+    ]
+
+testsVInt :: TestTree
+testsVInt =
+  testGroup
+    "Vector [] 6 Int"
+    [ testGroup "Additive" $ testLawOf ([] :: [Vector [] 6 Int]) <$> additiveLaws
+    , testGroup "Additive Group" $
+      testLawOf ([] :: [Vector [] 6 Int]) <$> additiveGroupLaws
+    , testGroup "Multiplicative" $
+      testLawOf ([] :: [Vector [] 6 Int]) <$> multiplicativeLaws
+    , testGroup "Distribution" $
+      testLawOf ([] :: [Vector [] 6 Int]) <$> distributionLaws
+    , testGroup "Additive Module" $
+      testLawOf2 ([] :: [(Vector [] 6 Int, Int)]) <$> additiveModuleLaws
+    , testGroup "Additive Group Module" $
+      testLawOf2 ([] :: [(Vector [] 6 Int, Int)]) <$> additiveGroupModuleLaws
+    , testGroup "Multiplicative Module" $
+      testLawOf2 ([] :: [(Vector [] 6 Int, Int)]) <$> multiplicativeModuleLaws
+    , testGroup "Hilbert" $
+      testLawOf2 ([] :: [(Vector [] 6 Int, Int)]) <$> hilbertLaws
+    , testGroup "Tensor product" $
+      testLawOf2 ([] :: [(Vector [] 6 Int, Int)]) <$> tensorProductLaws
+    , testGroup "Additive Basis" $
+      testLawOf ([] :: [Vector [] 6 Int]) <$> additiveBasisLaws
+    , testGroup "Additive Group Basis" $
+      testLawOf ([] :: [Vector [] 6 Int]) <$> additiveGroupBasisLaws
+    , testGroup "Multiplicative Basis" $
+      testLawOf ([] :: [Vector [] 6 Int]) <$> multiplicativeBasisLaws
+    ]
+
+testsMInt :: TestTree
+testsMInt =
+  testGroup
+    "Matrix [] 4 3 Int"
+    [ testGroup "Additive" $ testLawOf ([] :: [Matrix [] 4 3 Int]) <$> additiveLaws
+    , testGroup "Additive Group" $
+      testLawOf ([] :: [Matrix [] 4 3 Int]) <$> additiveGroupLaws
+    , testGroup "Multiplicative (square only)" $
+      testLawOf ([] :: [Matrix [] 3 3 Int]) <$> multiplicativeMonoidalLaws
+    , testGroup "Additive Module" $
+      testLawOf2 ([] :: [(Matrix [] 4 3 Int, Int)]) <$> additiveModuleLaws
+    , testGroup "Additive Group Module" $
+      testLawOf2 ([] :: [(Matrix [] 4 3 Int, Int)]) <$> additiveGroupModuleLaws
+    , testGroup "Multiplicative Module" $
+      testLawOf2 ([] :: [(Matrix [] 4 3 Int, Int)]) <$> multiplicativeModuleLaws
+    , testGroup "Hilbert" $
+      testLawOf2 ([] :: [(Matrix [] 4 3 Int, Int)]) <$> hilbertLaws
+    , testGroup "Tensor product" $
+      testLawOf2 ([] :: [(Matrix [] 4 3 Int, Int)]) <$> tensorProductLaws
+    , testGroup "Additive Basis" $
+      testLawOf ([] :: [Matrix [] 4 3 Int]) <$> additiveBasisLaws
+    , testGroup "Additive Group Basis" $
+      testLawOf ([] :: [Matrix [] 4 3 Int]) <$> additiveGroupBasisLaws
+    , testGroup "Multiplicative Basis" $
+      testLawOf ([] :: [Matrix [] 4 3 Int]) <$> multiplicativeBasisLaws
+    ]
+
+testsVFloat :: TestTree
+testsVFloat =
+  testGroup
+    "Vector 6 Float"
+    [ testGroup "MultiplicativeGroup" $
+      testLawOf ([] :: [Vector [] 6 Float]) <$> multiplicativeGroupLaws
+    , testGroup "Signed" $ testLawOf ([] :: [Vector [] 6 Float]) <$> signedLaws
+    , testGroup "Metric" $
+      testLawOf ([] :: [Vector [] 6 Float]) <$> metricNaperianFloatLaws
+    , testGroup "Exponential Field" $
+      testLawOf ([] :: [Vector [] 6 Float]) <$> expFieldNaperianLaws
+    , testGroup "Multiplicative Group Module" $
+      localOption (QuickCheckTests 1000) .
+      testLawOf2 ([] :: [(Vector [] 6 Float, Float)]) <$>
+      multiplicativeGroupModuleLawsFail
+    , testGroup "Multiplicative Group Basis" $
+      testLawOf ([] :: [Vector [] 6 Float]) <$> multiplicativeGroupBasisLaws
+    ]
+
+testsMFloat :: TestTree
+testsMFloat =
+  testGroup
+    "Matrix [] 4 3 Float"
+    [ testGroup "Multiplicative Group Module" $
+      localOption (QuickCheckTests 1000) .
+      testLawOf2 ([] :: [(Matrix [] 4 3 Float, Float)]) <$>
+      multiplicativeGroupModuleLawsFail
+    , testGroup "Multiplicative Group Basis" $
+      testLawOf ([] :: [Matrix [] 4 3 Float]) <$> multiplicativeGroupBasisLaws
+    ]
