diff --git a/Data/Array/Internal.hs b/Data/Array/Internal.hs
--- a/Data/Array/Internal.hs
+++ b/Data/Array/Internal.hs
@@ -30,7 +30,7 @@
 import Data.Data(Data)
 import qualified Data.DList as DL
 import Data.Kind (Type)
-import Data.List(foldl', zipWith4, zipWith5, sortBy, sortOn)
+import Data.List(foldl', zipWith4, zipWith5, sortBy, sortOn, foldl1')
 import Data.Proxy
 import GHC.Exts(Constraint, build)
 import GHC.Generics(Generic)
@@ -115,9 +115,6 @@
 prettyShowL :: (Pretty a) => PrettyLevel -> a -> String
 prettyShowL l = render . pPrintPrec l 0
 
--- We expect all N to be non-negative, but we use Int for convenience.
-type N = Int
-
 -- | The type /T/ is the internal type of arrays.  In general,
 -- operations on /T/ do no sanity checking as that should be done
 -- at the point of call.
@@ -128,8 +125,8 @@
 -- To find where item /i,j/ of the two outermost dimensions is you
 -- calculate vector index @offset + i*strides[0] + j*strides[1]@, etc.
 data T v a = T
-    { strides :: [N]      -- length is tensor rank
-    , offset  :: !N       -- offset into vector of values
+    { strides :: ![Int]   -- length is tensor rank
+    , offset  :: !Int     -- offset into vector of values
     , values  :: !(v a)   -- actual values
     }
     deriving (Show, Generic, Data)
@@ -143,7 +140,9 @@
 badShape = any (< 0)
 
 -- When shapes match, we can be efficient and use loop-fused comparisons instead
--- of materializing a list.
+-- of materializing a vector.
+-- Note this assumes the shape is the same for both Vectors.
+-- TODO(augustss): if the array is a small fraction of the vector this can be inefficient.
 {-# INLINABLE equalT #-}
 equalT :: (Vector v, VecElem v a, Eq a, Eq (v a))
                   => ShapeL -> T v a -> T v a -> Bool
@@ -161,7 +160,7 @@
 -- Given the dimensions, return the stride in the underlying vector
 -- for each dimension.  The first element of the list is the total length.
 {-# INLINE getStridesT #-}
-getStridesT :: ShapeL -> [N]
+getStridesT :: ShapeL -> [Int]
 getStridesT = scanr (*) 1
 
 -- Convert an array to a list by indexing through all the elements.
@@ -186,7 +185,7 @@
 -- | Check if the strides are canonical, i.e., if the vector have the natural layout.
 -- XXX Copy special cases from Tensor.
 {-# INLINE isCanonicalT #-}
-isCanonicalT :: (Vector v, VecElem v a) => [N] -> T v a -> Bool
+isCanonicalT :: (Vector v, VecElem v a) => [Int] -> T v a -> Bool
 isCanonicalT (n:ss') (T ss o v) =
     o == 0 &&         -- Vector offset is 0
     ss == ss' &&      -- All strides are normal
@@ -239,13 +238,14 @@
 
 -- Convert to a vector containing the right elements,
 -- but not necessarily in the right order.
+-- This is used for reduction with commutative&associative operations.
 {-# INLINE toUnorderedVectorT #-}
 toUnorderedVectorT :: (Vector v, VecElem v a) => ShapeL -> T v a -> v a
 toUnorderedVectorT sh a@(T ats ao v) =
   -- Figure out if the array maps onto some contiguous slice of the vector.
   -- Do this by checking if a transposition of the array corresponds to
   -- normal strides.
-  -- First sort the strides in descending order, amnd rearrange the shape the same way.
+  -- First sort the strides in descending order, and rearrange the shape the same way.
   -- Then compute the strides from this rearranged shape; these will be the normal
   -- strides for this shape.  If these strides agree with the sorted actual strides
   -- it is a transposition, and we can just slice out the relevant piece of the vector.
@@ -265,12 +265,12 @@
 
 -- Convert from a list
 {-# INLINE fromListT #-}
-fromListT :: (Vector v, VecElem v a) => [N] -> [a] -> T v a
+fromListT :: (Vector v, VecElem v a) => [Int] -> [a] -> T v a
 fromListT sh = fromVectorT sh . vFromList
 
 -- Index into the outermost dimension of an array.
 {-# INLINE indexT #-}
-indexT :: T v a -> N -> T v a
+indexT :: T v a -> Int -> T v a
 indexT (T (s : ss) o v) i = T ss (o + i * s) v
 indexT _ _ = error "impossible"
 
@@ -358,7 +358,7 @@
 
 -- Reverse the given dimensions.
 {-# INLINE reverseT #-}
-reverseT :: [N] -> ShapeL -> T v a -> T v a
+reverseT :: [Int] -> ShapeL -> T v a -> T v a
 reverseT rs sh (T ats ao v) = T rts ro v
   where (ro, rts) = rev 0 sh ats
         rev !_ [] [] = (ao, [])
@@ -395,45 +395,86 @@
         !x = vIndex v' 0
     in  vAll (x ==) v'
 
+newtype Rect = Rect { unRect :: [String] }  -- A rectangle of text
+
+toRect :: String -> Rect
+toRect = Rect . lines
+
+fromRect :: Rect -> String
+fromRect (Rect ls) = unlines ls
+
+-- Make each Rect be of size h * w
+rectPad :: Int -> Int -> Rect -> Rect
+rectPad h w (Rect ls) = Rect $ map padL ls ++ replicate (h - length ls) mt
+  where mt = replicate w ' '
+        padL s = replicate (w - length s) ' ' ++ s
+
+-- Horizontal catenation.  Assumes input rectangle are padded.
+-- Adds empty space between Rects.
+hcatRect :: Rect -> Rect -> Rect
+hcatRect (Rect xs) (Rect ys) = Rect $ zipWith (\ x y -> x ++ " " ++ y) xs ys
+
+-- Vertical catenation.  Assumes input rectangle are padded.
+-- Adds no space between Rects.
+vcatRect :: Rect -> Rect -> Rect
+vcatRect (Rect xs) (Rect ys) = Rect $ xs ++ ys
+
+rectHeight :: Rect -> Int
+rectHeight = length . unRect
+
+-- Widest line
+rectWidth :: Rect -> Int
+rectWidth = maximum . (0:) . map length . unRect
+
 ppT
   :: (Vector v, VecElem v a, Pretty a)
   => PrettyLevel -> Rational -> ShapeL -> T v a -> Doc
-ppT l p sh = maybeParens (p > 10) . vcat . map text .  box prettyBoxMode . ppT_ (prettyShowL l) sh
+ppT l p sh = maybeParens (p > 10) . vcat' . map text . unRect . box boxMode . ppT_ (prettyShowL l) sh
+  where boxMode | l >= prettyNormal = BoxMode True True True
+                | otherwise = BoxMode False False False
+        vcat' = foldl' ($+$) empty
 
 ppT_
   :: (Vector v, VecElem v a)
-  => (a -> String) -> ShapeL -> T v a -> String
-ppT_ show_ sh t = revDropWhile (== '\n') $ showsT sh t' ""
-  where ss = map show_ $ toListT sh t
-        n = maximum $ map length ss
-        ss' = map padSP ss
-        padSP s = replicate (n - length s) ' ' ++ s
-        t' :: T [] String
+  => (a -> String) -> ShapeL -> T v a -> Rect
+ppT_ show_ sh t = showsT sh t'
+  where ss = map (toRect . show_) $ toListT sh t
+        maxH = maximum $ map rectHeight ss
+        maxW = maximum $ map rectWidth ss
+        ss' = map (rectPad maxH maxW) ss
+        t' :: T [] Rect
         t' = T (tail (getStridesT sh)) 0 ss'
 
-showsT :: [N] -> T [] String -> ShowS
-showsT (0:_)  _ = showString "EMPTY"
-showsT []     t = showString $ unScalarT t
-showsT s@[_]  t = showString $ unwords $ toListT s t
-showsT (n:ns) t =
-    foldr (.) id [ showsT ns (indexT t i) . showString "\n" | i <- [0..n-1] ]
+showsT :: [Int] -> T [] Rect -> Rect
+showsT []     t = unScalarT t
+showsT s@[_]  t = foldl1' hcatRect $ toListT s t
+showsT (n:ns) t = foldl1' vcat' rs
+  where vcat' x y = vcatRect x (vcatRect spc y)
+        spc = Rect $ replicate (length ns - 1) (replicate (rectWidth (head rs)) ' ')
+        rs = [ showsT ns (indexT t i) | i <- [0..n-1] ]
 
 data BoxMode = BoxMode { _bmBars, _bmUnicode, _bmHeader :: Bool }
 
 prettyBoxMode :: BoxMode
 prettyBoxMode = BoxMode False False False
 
-box :: BoxMode -> String -> [String]
-box BoxMode{..} s =
+-- Possibly draw a box around a (padded) rectangle.
+box :: BoxMode -> Rect -> Rect
+box BoxMode{..} (Rect ls) =
   let bar | _bmUnicode = '\x2502'
           | otherwise = '|'
-      ls = lines s
+      dash | _bmUnicode = '\x2500'
+           | otherwise = '-'
       ls' | _bmBars = map (\ l -> if null l then l else [bar] ++ l ++ [bar]) ls
           | otherwise = ls
-      h = "+" ++ replicate (length (head ls)) '-' ++ "+"
-      ls'' | _bmHeader = [h] ++ ls' ++ [h]
+      h = replicate (length (head ls)) dash
+      t | _bmUnicode = "\x250c" ++ h ++ "\x2510"
+        | otherwise = "+" ++ h ++ "+"
+      b | _bmUnicode = "\x2514" ++ h ++ "\x2518"
+        | otherwise = t
+      ls'' | _bmHeader = [t] ++ ls' ++ [b]
            | otherwise = ls'
-  in  ls''
+  in  Rect ls''
 
 zipWithLong2 :: (a -> b -> b) -> [a] -> [b] -> [b]
 zipWithLong2 f (a:as) (b:bs) = f a b : zipWithLong2 f as bs
@@ -453,7 +494,7 @@
 -- size 1, in which case it can be done by just manipulating
 -- the strides.  Given the old strides, the old shapes, and the
 -- new shape it will return the possible new strides.
-simpleReshape :: [N] -> ShapeL -> ShapeL -> Maybe [N]
+simpleReshape :: [Int] -> ShapeL -> ShapeL -> Maybe [Int]
 simpleReshape osts os ns
   | filter (1 /=) os == filter (1 /=) ns = Just $ loop ns sts'
     -- Old and new dimensions agree where they are not 1.
@@ -467,18 +508,22 @@
       loop _ _ = error $ "simpleReshape: shouldn't happen: " ++ show (osts, os, ns)
 simpleReshape _ _ _ = Nothing
 
+-- Note: assumes + is commutative&associative.
 {-# INLINE sumT #-}
 sumT :: (Vector v, VecElem v a, Num a) => ShapeL -> T v a -> a
 sumT sh = vSum . toUnorderedVectorT sh
 
+-- Note: assumes * is commutative&associative.
 {-# INLINE productT #-}
 productT :: (Vector v, VecElem v a, Num a) => ShapeL -> T v a -> a
 productT sh = vProduct . toUnorderedVectorT sh
 
+-- Note: assumes max is commutative&associative.
 {-# INLINE maximumT #-}
 maximumT :: (Vector v, VecElem v a, Ord a) => ShapeL -> T v a -> a
 maximumT sh = vMaximum . toUnorderedVectorT sh
 
+-- Note: assumes min is commutative&associative.
 {-# INLINE minimumT #-}
 minimumT :: (Vector v, VecElem v a, Ord a) => ShapeL -> T v a -> a
 minimumT sh = vMinimum . toUnorderedVectorT sh
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -93,11 +93,15 @@
 Arrays can be pretty printed.  They are shown in the APL way:
 The innermost dimension on a line, the next dimension vertically,
 the next dimension vertically with an empty line in between, and so on.
+Normally there is a box drawn around the array, but this can be changed by lowering
+pretty printing level to `pPrintPrec`.
 
 ```
 > pp m
-1 2 3
-4 5 6
+┌─────┐
+│1 2 3│
+│4 5 6│
+└─────┘
 ```
 
 We can have an arbitrary number of dimensions.
@@ -107,32 +111,44 @@
 > v = fromList [3] [7,8,9]
 > a = fromList [2,3,4] [1..24]
 > pp s
-42
+┌──┐
+│42│
+└──┘
 > pp v
-7 8 9
+┌─────┐
+│7 8 9│
+└─────┘
 > pp a
- 1  2  3  4
- 5  6  7  8
- 9 10 11 12
-
-13 14 15 16
-17 18 19 20
-21 22 23 24
+┌───────────┐
+│ 1  2  3  4│
+│ 5  6  7  8│
+│ 9 10 11 12│
+│           │
+│13 14 15 16│
+│17 18 19 20│
+│21 22 23 24│
+└───────────┘
 ```
 
 Indexing into an array removes the outermost dimension of it by selecting a subarray with the given index.
 
 ```
 > pp $ index v 1
-8
+┌─┐
+│8│
+└─┘
 > shapeL $ index v 1
 []
 > pp $ index a 1
-13 14 15 16
-17 18 19 20
-21 22 23 24
+┌───────────┐
+│13 14 15 16│
+│17 18 19 20│
+│21 22 23 24│
+└───────────┘
 > pp $ a `index` 1 `index` 2 `index` 0
-21
+┌──┐
+│21│
+└──┘
 ```
 
 The `scalar` and `unScalar` functions can be used to convert an element to/from and array.
@@ -149,16 +165,20 @@
 
 ```
 > pp $ constant [2,3] 8
-8 8 8
-8 8 8
+┌─────┐
+│8 8 8│
+│8 8 8│
+└─────┘
 ```
 
 Arrays are also instances of `Functor`, `Foldable`, and `Traversable`.
 
 ```
 > pp $ fmap succ v
- 8  9 10
-foldr (+) 0 a
+┌────────┐
+│ 8  9 10│
+└────────┘
+> foldr (+) 0 a
 300
 ```
 
@@ -171,14 +191,16 @@
 > shapeL (transpose [1,0,2] a)
 [3,2,4]
 > pp $ transpose [1,0,2] a
- 1  2  3  4
-13 14 15 16
-
- 5  6  7  8
-17 18 19 20
-
- 9 10 11 12
-21 22 23 24
+┌───────────┐
+│ 1  2  3  4│
+│13 14 15 16│
+│           │
+│ 5  6  7  8│
+│17 18 19 20│
+│           │
+│ 9 10 11 12│
+│21 22 23 24│
+└───────────┘
 ```
 
 The `reshape` operation keeps the elements of an array,
@@ -186,13 +208,70 @@
 
 ```
 > pp $ reshape [3,8] a
- 1  2  3  4  5  6  7  8
- 9 10 11 12 13 14 15 16
-17 18 19 20 21 22 23 24
+┌───────────────────────┐
+│ 1  2  3  4  5  6  7  8│
+│ 9 10 11 12 13 14 15 16│
+│17 18 19 20 21 22 23 24│
+└───────────────────────┘
 ```
 
+An array can be turned into an array of arrays, where the outermost
+array will have rank 1.
+```
+> pp $ unravel a
+┌───────────────────────────┐
+│┌───────────┐ ┌───────────┐│
+││ 1  2  3  4│ │13 14 15 16││
+││ 5  6  7  8│ │17 18 19 20││
+││ 9 10 11 12│ │21 22 23 24││
+│└───────────┘ └───────────┘│
+└───────────────────────────┘
+```
 
+The `foldr` operation reduces an array to something of the element type.
+Using `reduce` you will instead get an array result.
+```
+> pp $ reduce (+) 0 a
+┌───┐
+│300│
+└───┘
+```
 
+Note how this operated on the entire array.  Using `rerank` it is possible
+to use a function "deeper down".
+```
+> pp $ rerank 1 (reduce (+) 0) a
+┌───────┐
+│ 78 222│
+└───────┘
+> pp $ rerank 2 (reduce (+) 0) a
+┌────────┐
+│10 26 42│
+│58 74 90│
+└────────┘
+> pp $ rerank 3 (reduce (+) 0) a
+┌───────────┐
+│ 1  2  3  4│
+│ 5  6  7  8│
+│ 9 10 11 12│
+│           │
+│13 14 15 16│
+│17 18 19 20│
+│21 22 23 24│
+└───────────┘
+```
+
+To reduce along some dimension(s) that are not the innermost we can make them innermost by transpostion.
+So to sum the columns:
+```
+> pp $ rerank 2 (reduce (+) 0) $ transpose [0,2,1] a
+┌───────────┐
+│15 18 21 24│
+│51 54 57 60│
+└───────────┘
+```
+
+
 ### Similar examples using `Shaped`
 
 ```
@@ -230,15 +309,19 @@
 ```
 > import Data.Array.Shaped.Instances
 > pp $ v * 2
-14 16 18
+┌────────┐
+│14 16 18│
+└────────┘
 > pp $ a + a
- 2  4  6  8
-10 12 14 16
-18 20 22 24
-
-26 28 30 32
-34 36 38 40
-42 44 46 48
+┌───────────┐
+│ 2  4  6  8│
+│10 12 14 16│
+│18 20 22 24│
+│           │
+│26 28 30 32│
+│34 36 38 40│
+│42 44 46 48│
+└───────────┘
 ```
 
 What is value arguments for `Dynamic` arrays sometimes turn into type arguments
@@ -246,8 +329,10 @@
 
 ```
 > pp $ reshape @[3,8] a
- 1  2  3  4  5  6  7  8
- 9 10 11 12 13 14 15 16
-17 18 19 20 21 22 23 24
+┌───────────────────────┐
+│ 1  2  3  4  5  6  7  8│
+│ 9 10 11 12 13 14 15 16│
+│17 18 19 20 21 22 23 24│
+└───────────────────────┘
 ```
 
diff --git a/orthotope.cabal b/orthotope.cabal
--- a/orthotope.cabal
+++ b/orthotope.cabal
@@ -1,5 +1,5 @@
 name:                orthotope
-version:             0.1.5.0
+version:             0.1.6.0
 synopsis:            Multidimensional arrays inspired by APL
 license:             Apache
 license-file:        LICENSE
@@ -18,7 +18,7 @@
       LICENSE
       README.md
 
-tested-with:         GHC ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.5 || ==9.6.2
+tested-with:         GHC ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.5 || ==9.6.1 || ==9.6.2
 
 source-repository head
     type:     git
@@ -76,10 +76,13 @@
 
   other-modules:       DynamicTest
                      , DynamicUTest
+                     , DynamicSTest
                      , RankedTest
                      , RankedUTest
+                     , RankedSTest
                      , ShapedTest
                      , ShapedUTest
+                     , ShapedSTest
 
   ghc-options:
     -Wall -rtsopts
diff --git a/tests/DynamicSTest.hs b/tests/DynamicSTest.hs
new file mode 100644
--- /dev/null
+++ b/tests/DynamicSTest.hs
@@ -0,0 +1,298 @@
+-- Copyright 2020 Google LLC
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--      http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+{-# LANGUAGE ScopedTypeVariables #-}
+module DynamicSTest(test) where
+
+import Control.DeepSeq
+import Control.Exception
+import Data.Array.DynamicS
+import qualified Data.Vector.Storable as V
+import Test.Framework (Test, testGroup)
+import Test.Framework.Providers.HUnit (testCase)
+import Test.HUnit (assertEqual, assertFailure, Assertion)
+
+assertThrows :: (NFData a) => String -> a -> Assertion
+assertThrows s a = catch (deepseq a $ assertFailure s) (\ (_ :: ErrorCall) -> return ())
+
+test :: Test
+test = testGroup "DynamicS" $
+  let a1, a2 :: Array Int
+      a1 = fromList [2,3] [1..6]
+      a2 = transpose [1,0] a1
+      show_1 = assertEqual "1" "fromList [2,3] [1,2,3,4,5,6]" (show a1)
+      show_2 = assertEqual "2" "fromList [3,2] [1,4,2,5,3,6]" (show a2)
+      eq_1 = assertEqual "1" True (a1 == a1)
+      eq_2 = assertEqual "2" False (a1 == a2)
+      ord_1 = assertEqual "1" EQ (a1 `compare` a1)
+      ord_2 = assertEqual "2" LT (a1 `compare` a2)
+      shapeL_1 = assertEqual "1" [2,3] (shapeL a1)
+      shapeL_2 = assertEqual "2" [3,2] (shapeL a2)
+      rank_1 = assertEqual "1" 2 (rank a1)
+      rank_2 = assertEqual "2" 2 (rank a2)
+      index_1 = assertEqual "1" (fromList [3] [1,2,3]) (index a1 0)
+      index_2 = assertEqual "2" (fromList [2] [1,4]) (index a2 0)
+      index_3 = assertEqual "3" (fromList [] [4]) (a2 `index` 0 `index` 1)
+      index_4 = assertThrows "<0" (index a1 (-1))
+      index_5 = assertThrows ">" (index a1 2)
+      toList_1 = assertEqual "1" [1,2,3,4,5,6] (toList a1)
+      toList_2 = assertEqual "2" [1,4,2,5,3,6] (toList a2)
+      toVector_1 = assertEqual "1" (V.fromList [1,2,3,4,5,6]) (toVector a1)
+      toVector_2 = assertEqual "2" (V.fromList [1,4,2,5,3,6]) (toVector a2)
+      fromList_1 = assertThrows "sh" (fromList [] [1,2::Int])
+      fromList_2 = assertThrows "sh" (fromList [4,5] [1,2::Int])
+      fromVector_1 = assertEqual "1" a1 (fromVector [2,3] $ V.fromList [1..6])
+      normalize_1 = assertEqual "1" a1 (normalize a1)
+      reshape_1 = assertEqual "1" (fromList [6] [1..6]) (reshape [6] a1)
+      reshape_2 = assertEqual "1" (fromList [1,2,3,1] [1,4,2,5,3,6]) (reshape [1,2,3,1] a2)
+      a3, a4 :: Array Int
+      a3 = fromList [1] [5]
+      a4 = fromList [] [5]
+      stretch_1 = assertEqual "1" (fromList [3] [5,5,5]) (stretch [3] a3)
+      stretch_2 = assertEqual "2" (fromList [2,2,3,2] [1,1,2,2,3,3,4,4,5,5,6,6,1,1,2,2,3,3,4,4,5,5,6,6])
+                                  (stretch [2,2,3,2] $ reshape [1,2,3,1] a1)
+      stretch_3 = assertThrows "3" (stretch [1,2] a3)
+      stretch_4 = assertThrows "4" (stretch [4,3] a1)
+      scalar_1 = assertEqual "1" a4 (scalar 5)
+      unScalar_1 = assertEqual "1" 5 (unScalar a4)
+      unScalar_2 = assertThrows "2" (unScalar a3)
+      constant_1 = assertEqual "1" (fromList [2,3] [1,1,1,1,1,1]) (constant [2,3] (1::Int))
+      mapA_1 = assertEqual "1" (fromList [2,3] [2..7]) (mapA succ a1)
+      mapA_2 = assertEqual "1" (fromList [3,2] [2,5,3,6,4,7]) (mapA succ a2)
+      zipWithA_1 = assertEqual "1" (fromList [2,3] [2,4..12]) (zipWithA (+) a1 a1)
+      zipWithA_2 = assertThrows "2" (zipWithA (+) a1 a2)
+      zipWith3A_1 = assertEqual "1" (fromList [2,3] [2,6,12,20,30,42]) (zipWith3A (\ x y z -> x*y+z) a1 a1 a1)
+      pad_1 = assertEqual "1" (fromList [5,10] [9,9,9,9,9,9,9,9,9,9,
+                                                9,9,9,1,2,3,9,9,9,9,
+                                                9,9,9,4,5,6,9,9,9,9,
+                                                9,9,9,9,9,9,9,9,9,9,
+                                                9,9,9,9,9,9,9,9,9,9])
+                              (pad [(1,2),(3,4)] 9 a1)
+      pad_2 = assertThrows "2" (pad [(1,1),(1,1),(1,1)] 0 a1)
+      a5 :: Array Int
+      a5 = fromList [2,3,4] [1..24]
+      transpose_1 = assertEqual "1" (fromList [2,3,4] [1,2,3,4,
+                                                       5,6,7,8,
+                                                       9,10,11,12,
+
+                                                       13,14,15,16,
+                                                       17,18,19,20,
+                                                       21,22,23,24])
+                                    (transpose [0,1,2] a5)
+      transpose_2 = assertEqual "2" (fromList [2,4,3] [1,5,9,
+                                                       2,6,10,
+                                                       3,7,11,
+                                                       4,8,12,
+
+                                                       13,17,21,
+                                                       14,18,22,
+                                                       15,19,23,
+                                                       16,20,24])
+                                    (transpose [0,2,1] a5)
+      transpose_3 = assertEqual "3" (fromList [3,2,4] [1,2,3,4,
+                                                       13,14,15,16,
+
+                                                       5,6,7,8,
+                                                       17,18,19,20,
+
+                                                       9,10,11,12,
+                                                       21,22,23,24])
+                                    (transpose [1,0,2] a5)
+      transpose_4 = assertEqual "4" (fromList [3,4,2] [1,13,
+                                                       2,14,
+                                                       3,15,
+                                                       4,16,
+
+                                                       5,17,
+                                                       6,18,
+                                                       7,19,
+                                                       8,20,
+
+                                                       9,21,
+                                                       10,22,
+                                                       11,23,
+                                                       12,24])
+                                    (transpose [1,2,0] a5)
+      transpose_5 = assertEqual "5" (fromList [4,2,3] [1,5,9,
+                                                       13,17,21,
+
+                                                       2,6,10,
+
+                                                       14,18,22,
+
+                                                       3,7,11,
+                                                       15,19,23,
+
+                                                       4,8,12,
+                                                       16,20,24])
+                                    (transpose [2,0,1] a5)
+      transpose_6 = assertEqual "6" (fromList [4,3,2] [1,13,
+                                                       5,17,
+                                                       9,21,
+
+                                                       2,14,
+                                                       6,18,
+                                                       10,22,
+
+                                                       3,15,
+                                                       7,19,
+                                                       11,23,
+
+                                                       4,16,
+                                                       8,20,
+                                                       12,24])
+                                    (transpose [2,1,0] a5)
+      transpose_7 = assertThrows "7" (transpose [0,1,2,3] a5)
+      transpose_8 = assertThrows "7" (transpose [0,1,3] a5)
+      transpose_9 = assertEqual "9" (fromList [3,2,4] [1,2,3,4,
+                                                       13,14,15,16,
+
+                                                       5,6,7,8,
+                                                       17,18,19,20,
+
+                                                       9,10,11,12,
+                                                       21,22,23,24])
+                                    (transpose [1,0] a5)
+      append_1 = assertEqual "1" (fromList [3,3] [1..9])
+                                 (append a1 (fromList [1,3] [7,8,9]))
+      concatOuter_1 = assertEqual "1" (fromList [6,3] [1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6])
+                                      (concatOuter [a1, concatOuter [a1,a1]])
+      concatOuter_2 = assertThrows "2" (concatOuter [a1, a2])
+      a6 :: Array Int
+      a6 = fromList [4,5] [1..20]
+      window_1 = assertEqual "1" (fromList [2,3,3,3] [1,2,3,
+                                                      6,7,8,
+                                                      11,12,13,
+
+                                                      2,3,4,
+                                                      7,8,9,
+                                                      12,13,14,
+
+                                                      3,4,5,
+                                                      8,9,10,
+                                                      13,14,15,
+
+
+                                                      6,7,8,
+                                                      11,12,13,
+                                                      16,17,18,
+
+                                                      7,8,9,
+                                                      12,13,14,
+                                                      17,18,19,
+
+                                                      8,9,10,
+                                                      13,14,15,
+                                                      18,19,20])
+                                 (window [3,3] a6)
+      window_2 = assertThrows "2" (window [3,6] a6)
+      window_3 = assertThrows "3" (window [3,3,3] a6)
+      stride_1 = assertEqual "1" (fromList [2,2,2] [1,3,
+                                                    9,11,
+
+                                                    13,15,
+                                                    21,23])
+                                 (stride [1,2,2] a5)
+      stride_2 = assertThrows "2" (stride [1,2,2] a1)
+      slice_1 = assertEqual "1" (fromList [2,2,1] [8,12,20,24])
+                                (slice [(0,2),(1,2),(3,1)] a5)
+      slice_2 = assertThrows "2" (slice [(0,0)] a4)
+      slice_3 = assertThrows "3" (slice [(-1,1)] a5)
+      slice_4 = assertThrows "4" (slice [(10,0)] a5)
+      slice_5 = assertThrows "5" (slice [(0,3)] a5)
+      a7 = mapA succ a5
+      dot x y = reduce (+) 0 $ zipWithA (*) x y
+      rerank2_1 = assertEqual "1" (fromList [2,3] [40,200,488,904,1448,2120])
+                                  (rerank2 2 dot a5 a7)
+      rev_1 = assertEqual "1" (fromList [2,3] [3,2,1,6,5,4])
+                              (rev [1] a1)
+      rev_2 = assertEqual "2" (fromList [2,3] [6,5,4,3,2,1])
+                              (rev [0,1] a1)
+      rev_3 = assertThrows "3" (rev [2] a1)
+      reduce_1 = assertEqual "1" (scalar 720) (reduce (*) 1 a1)
+      reduce_2 = assertEqual "2" (fromList [2] [6,120]) (rerank 1 (reduce (*) 1) a1)
+      reduce_3 = assertEqual "3" (fromList [3] [4,10,18]) (rerank 1 (reduce (*) 1) a2)
+
+      tests =
+        [ testCase "show_1" show_1
+        , testCase "show_2" show_2
+        , testCase "eq_1" eq_1
+        , testCase "eq_2" eq_2
+        , testCase "ord_1" ord_1
+        , testCase "ord_2" ord_2
+        , testCase "shapeL_1" shapeL_1
+        , testCase "shapeL_2" shapeL_2
+        , testCase "rank_1" rank_1
+        , testCase "rank_2" rank_2
+        , testCase "index_1" index_1
+        , testCase "index_2" index_2
+        , testCase "index_3" index_3
+        , testCase "index_4" index_4
+        , testCase "index_5" index_5
+        , testCase "toList_1" toList_1
+        , testCase "toList_2" toList_2
+        , testCase "toVector_1" toVector_1
+        , testCase "toVector_2" toVector_2
+        , testCase "fromList_1" fromList_1
+        , testCase "fromList_2" fromList_2
+        , testCase "fromVector_1" fromVector_1
+        , testCase "normalize_1" normalize_1
+        , testCase "reshape_1" reshape_1
+        , testCase "reshape_2" reshape_2
+        , testCase "stretch_1" stretch_1
+        , testCase "stretch_2" stretch_2
+        , testCase "stretch_3" stretch_3
+        , testCase "stretch_4" stretch_4
+        , testCase "scalar_1" scalar_1
+        , testCase "unScalar_1" unScalar_1
+        , testCase "unScalar_2" unScalar_2
+        , testCase "constant_1" constant_1
+        , testCase "mapA_1" mapA_1
+        , testCase "mapA_2" mapA_2
+        , testCase "zipWithA_1" zipWithA_1
+        , testCase "zipWithA_2" zipWithA_2
+        , testCase "zipWith3A_1" zipWith3A_1
+        , testCase "pad_1" pad_1
+        , testCase "pad_2" pad_2
+        , testCase "transpose_1" transpose_1
+        , testCase "transpose_2" transpose_2
+        , testCase "transpose_3" transpose_3
+        , testCase "transpose_4" transpose_4
+        , testCase "transpose_5" transpose_5
+        , testCase "transpose_6" transpose_6
+        , testCase "transpose_7" transpose_7
+        , testCase "transpose_8" transpose_8
+        , testCase "transpose_9" transpose_9
+        , testCase "append_1" append_1
+        , testCase "concatOuter_1" concatOuter_1
+        , testCase "concatOuter_2" concatOuter_2
+        , testCase "window_1" window_1
+        , testCase "window_2" window_2
+        , testCase "window_3" window_3
+        , testCase "stride_1" stride_1
+        , testCase "stride_2" stride_2
+        , testCase "slice_1" slice_1
+        , testCase "slice_2" slice_2
+        , testCase "slice_3" slice_3
+        , testCase "slice_4" slice_4
+        , testCase "slice_5" slice_5
+        , testCase "rerank2_1" rerank2_1
+        , testCase "rev_1" rev_1
+        , testCase "rev_2" rev_2
+        , testCase "rev_3" rev_3
+        , testCase "reduce_1" reduce_1
+        , testCase "reduce_2" reduce_2
+        , testCase "reduce_3" reduce_3
+        ]
+  in  tests
diff --git a/tests/RankedSTest.hs b/tests/RankedSTest.hs
new file mode 100644
--- /dev/null
+++ b/tests/RankedSTest.hs
@@ -0,0 +1,299 @@
+-- Copyright 2020 Google LLC
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--      http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module RankedSTest(test) where
+
+import Control.DeepSeq
+import Control.Exception
+import Data.Array.RankedS
+import qualified Data.Vector.Storable as V
+import Test.Framework (Test, testGroup)
+import Test.Framework.Providers.HUnit (testCase)
+import Test.HUnit (assertEqual, assertFailure, Assertion)
+
+assertThrows :: (NFData a) => String -> a -> Assertion
+assertThrows s a = catch (deepseq a $ assertFailure s) (\ (_ :: ErrorCall) -> return ())
+
+test :: Test
+test = testGroup "RankedS" $
+  let a1, a2 :: Array 2 Int
+      a1 = fromList [2,3] [1..6]
+      a2 = transpose [1,0] a1
+      show_1 = assertEqual "1" "fromList [2,3] [1,2,3,4,5,6]" (show a1)
+      show_2 = assertEqual "2" "fromList [3,2] [1,4,2,5,3,6]" (show a2)
+      eq_1 = assertEqual "1" True (a1 == a1)
+      eq_2 = assertEqual "2" False (a1 == a2)
+      ord_1 = assertEqual "1" EQ (a1 `compare` a1)
+      ord_2 = assertEqual "2" LT (a1 `compare` a2)
+      shapeL_1 = assertEqual "1" [2,3] (shapeL a1)
+      shapeL_2 = assertEqual "2" [3,2] (shapeL a2)
+      rank_1 = assertEqual "1" 2 (rank a1)
+      rank_2 = assertEqual "2" 2 (rank a2)
+      index_1 = assertEqual "1" (fromList [3] [1,2,3]) (index a1 0)
+      index_2 = assertEqual "2" (fromList [2] [1,4]) (index a2 0)
+      index_3 = assertEqual "3" (fromList [] [4]) (a2 `index` 0 `index` 1)
+      index_4 = assertThrows "<0" (index a1 (-1))
+      index_5 = assertThrows ">" (index a1 2)
+      toList_1 = assertEqual "1" [1,2,3,4,5,6] (toList a1)
+      toList_2 = assertEqual "2" [1,4,2,5,3,6] (toList a2)
+      toVector_1 = assertEqual "1" (V.fromList [1,2,3,4,5,6]) (toVector a1)
+      toVector_2 = assertEqual "2" (V.fromList [1,4,2,5,3,6]) (toVector a2)
+      fromList_1 = assertThrows "sh" (fromList [] [1,2] :: Array 0 Int)
+      fromList_2 = assertThrows "sh" (fromList [4,5] [1,2] :: Array 2 Int)
+      fromVector_1 = assertEqual "1" a1 (fromVector [2,3] $ V.fromList [1..6])
+      normalize_1 = assertEqual "1" a1 (normalize a1)
+      reshape_1 = assertEqual "1" (fromList [6] [1..6] :: Array 1 Int) (reshape [6] a1)
+      reshape_2 = assertEqual "1" (fromList [1,2,3,1] [1,4,2,5,3,6]) (reshape [1,2,3,1] a2 :: Array 4 Int)
+      a3 :: Array 1 Int
+      a3 = fromList [1] [5]
+      a4 :: Array 0 Int
+      a4 = fromList [] [5]
+      stretch_1 = assertEqual "1" (fromList [3] [5,5,5]) (stretch [3] a3)
+      stretch_2 = assertEqual "2" (fromList [2,2,3,2] [1,1,2,2,3,3,4,4,5,5,6,6,1,1,2,2,3,3,4,4,5,5,6,6])
+                                  (stretch [2,2,3,2] (reshape [1,2,3,1] a1 :: Array 4 Int))
+      stretch_3 = assertThrows "3" (stretch [1,2] a3)
+      stretch_4 = assertThrows "4" (stretch [4,3] a1)
+      scalar_1 = assertEqual "1" a4 (scalar 5)
+      unScalar_1 = assertEqual "1" 5 (unScalar a4)
+      constant_1 = assertEqual "1" (fromList [2,3] [1,1,1,1,1,1]) (constant [2,3] 1 :: Array 2 Int)
+      mapA_1 = assertEqual "1" (fromList [2,3] [2..7]) (mapA succ a1)
+      mapA_2 = assertEqual "1" (fromList [3,2] [2,5,3,6,4,7]) (mapA succ a2)
+      zipWithA_1 = assertEqual "1" (fromList [2,3] [2,4..12]) (zipWithA (+) a1 a1)
+      zipWithA_2 = assertThrows "2" (zipWithA (+) a1 a2)
+      zipWith3A_1 = assertEqual "1" (fromList [2,3] [2,6,12,20,30,42]) (zipWith3A (\ x y z -> x*y+z) a1 a1 a1)
+      pad_1 = assertEqual "1" (fromList [5,10] [9,9,9,9,9,9,9,9,9,9,
+                                                9,9,9,1,2,3,9,9,9,9,
+                                                9,9,9,4,5,6,9,9,9,9,
+                                                9,9,9,9,9,9,9,9,9,9,
+                                                9,9,9,9,9,9,9,9,9,9])
+                              (pad [(1,2),(3,4)] 9 a1)
+      pad_2 = assertThrows "2" (pad [(1,1),(1,1),(1,1)] 0 a1)
+      a5 :: Array 3 Int
+      a5 = fromList [2,3,4] [1..24]
+      transpose_1 = assertEqual "1" (fromList [2,3,4] [1,2,3,4,
+                                                       5,6,7,8,
+                                                       9,10,11,12,
+
+                                                       13,14,15,16,
+                                                       17,18,19,20,
+                                                       21,22,23,24])
+                                    (transpose [0,1,2] a5)
+      transpose_2 = assertEqual "2" (fromList [2,4,3] [1,5,9,
+                                                       2,6,10,
+                                                       3,7,11,
+                                                       4,8,12,
+
+                                                       13,17,21,
+                                                       14,18,22,
+                                                       15,19,23,
+                                                       16,20,24])
+                                    (transpose [0,2,1] a5)
+      transpose_3 = assertEqual "3" (fromList [3,2,4] [1,2,3,4,
+                                                       13,14,15,16,
+
+                                                       5,6,7,8,
+                                                       17,18,19,20,
+
+                                                       9,10,11,12,
+                                                       21,22,23,24])
+                                    (transpose [1,0,2] a5)
+      transpose_4 = assertEqual "4" (fromList [3,4,2] [1,13,
+                                                       2,14,
+                                                       3,15,
+                                                       4,16,
+
+                                                       5,17,
+                                                       6,18,
+                                                       7,19,
+                                                       8,20,
+
+                                                       9,21,
+                                                       10,22,
+                                                       11,23,
+                                                       12,24])
+                                    (transpose [1,2,0] a5)
+      transpose_5 = assertEqual "5" (fromList [4,2,3] [1,5,9,
+                                                       13,17,21,
+
+                                                       2,6,10,
+
+                                                       14,18,22,
+
+                                                       3,7,11,
+                                                       15,19,23,
+
+                                                       4,8,12,
+                                                       16,20,24])
+                                    (transpose [2,0,1] a5)
+      transpose_6 = assertEqual "6" (fromList [4,3,2] [1,13,
+                                                       5,17,
+                                                       9,21,
+
+                                                       2,14,
+                                                       6,18,
+                                                       10,22,
+
+                                                       3,15,
+                                                       7,19,
+                                                       11,23,
+
+                                                       4,16,
+                                                       8,20,
+                                                       12,24])
+                                    (transpose [2,1,0] a5)
+      transpose_7 = assertThrows "7" (transpose [0,1,2,3] a5)
+      transpose_8 = assertThrows "7" (transpose [0,1,3] a5)
+      transpose_9 = assertEqual "9" (fromList [3,2,4] [1,2,3,4,
+                                                       13,14,15,16,
+
+                                                       5,6,7,8,
+                                                       17,18,19,20,
+
+                                                       9,10,11,12,
+                                                       21,22,23,24])
+                                    (transpose [1,0] a5)
+      append_1 = assertEqual "1" (fromList [3,3] [1..9])
+                                 (append a1 (fromList [1,3] [7,8,9]))
+      concatOuter_1 = assertEqual "1" (fromList [6,3] [1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6])
+                                      (concatOuter [a1, concatOuter [a1,a1]])
+      concatOuter_2 = assertThrows "2" (concatOuter [a1, a2])
+      a6 :: Array 2 Int
+      a6 = fromList [4,5] [1..20]
+      window_1 = assertEqual "1" (fromList [2,3,3,3] [1,2,3,
+                                                      6,7,8,
+                                                      11,12,13,
+
+                                                      2,3,4,
+                                                      7,8,9,
+                                                      12,13,14,
+
+                                                      3,4,5,
+                                                      8,9,10,
+                                                      13,14,15,
+
+
+                                                      6,7,8,
+                                                      11,12,13,
+                                                      16,17,18,
+
+                                                      7,8,9,
+                                                      12,13,14,
+                                                      17,18,19,
+
+                                                      8,9,10,
+                                                      13,14,15,
+                                                      18,19,20])
+                                 (window [3,3] a6 :: Array 4 Int)
+      window_2 = assertThrows "2" (window [3,6] a6 :: Array 4 Int)
+      window_3 = assertThrows "3" (window [3,3,3] a6 :: Array 5 Int)
+      stride_1 = assertEqual "1" (fromList [2,2,2] [1,3,
+                                                    9,11,
+
+                                                    13,15,
+                                                    21,23])
+                                 (stride [1,2,2] a5)
+      stride_2 = assertThrows "2" (stride [1,2,2] a1)
+      slice_1 = assertEqual "1" (fromList [2,2,1] [8,12,20,24])
+                                (slice [(0,2),(1,2),(3,1)] a5)
+      slice_2 = assertThrows "2" (slice [(0,0)] a4)
+      slice_3 = assertThrows "3" (slice [(-1,1)] a5)
+      slice_4 = assertThrows "4" (slice [(10,0)] a5)
+      slice_5 = assertThrows "5" (slice [(0,3)] a5)
+      a7 = mapA succ a5
+      dot x y = reduce (+) 0 $ zipWithA (*) x y
+      rerank2_1 = assertEqual "1" (fromList [2,3] [40,200,488,904,1448,2120])
+                                  (rerank2 @2 dot a5 a7)
+      rev_1 = assertEqual "1" (fromList [2,3] [3,2,1,6,5,4])
+                              (rev [1] a1)
+      rev_2 = assertEqual "2" (fromList [2,3] [6,5,4,3,2,1])
+                              (rev [0,1] a1)
+      rev_3 = assertThrows "3" (rev [2] a1)
+      reduce_1 = assertEqual "1" (scalar 720) (reduce (*) 1 a1)
+      reduce_2 = assertEqual "2" (fromList [2] [6,120]) (rerank @1 (reduce (*) 1) a1)
+      reduce_3 = assertEqual "3" (fromList [3] [4,10,18]) (rerank @1 (reduce (*) 1) a2)
+
+      tests =
+        [ testCase "show_1" show_1
+        , testCase "show_2" show_2
+        , testCase "eq_1" eq_1
+        , testCase "eq_2" eq_2
+        , testCase "ord_1" ord_1
+        , testCase "ord_2" ord_2
+        , testCase "shapeL_1" shapeL_1
+        , testCase "shapeL_2" shapeL_2
+        , testCase "rank_1" rank_1
+        , testCase "rank_2" rank_2
+        , testCase "index_1" index_1
+        , testCase "index_2" index_2
+        , testCase "index_3" index_3
+        , testCase "index_4" index_4
+        , testCase "index_5" index_5
+        , testCase "toList_1" toList_1
+        , testCase "toList_2" toList_2
+        , testCase "toVector_1" toVector_1
+        , testCase "toVector_2" toVector_2
+        , testCase "fromList_1" fromList_1
+        , testCase "fromList_2" fromList_2
+        , testCase "fromVector_1" fromVector_1
+        , testCase "normalize_1" normalize_1
+        , testCase "reshape_1" reshape_1
+        , testCase "reshape_2" reshape_2
+        , testCase "stretch_1" stretch_1
+        , testCase "stretch_2" stretch_2
+        , testCase "stretch_3" stretch_3
+        , testCase "stretch_4" stretch_4
+        , testCase "scalar_1" scalar_1
+        , testCase "unScalar_1" unScalar_1
+        , testCase "constant_1" constant_1
+        , testCase "mapA_1" mapA_1
+        , testCase "mapA_2" mapA_2
+        , testCase "zipWithA_1" zipWithA_1
+        , testCase "zipWithA_2" zipWithA_2
+        , testCase "zipWith3A_1" zipWith3A_1
+        , testCase "pad_1" pad_1
+        , testCase "pad_2" pad_2
+        , testCase "transpose_1" transpose_1
+        , testCase "transpose_2" transpose_2
+        , testCase "transpose_3" transpose_3
+        , testCase "transpose_4" transpose_4
+        , testCase "transpose_5" transpose_5
+        , testCase "transpose_6" transpose_6
+        , testCase "transpose_7" transpose_7
+        , testCase "transpose_8" transpose_8
+        , testCase "transpose_9" transpose_9
+        , testCase "append_1" append_1
+        , testCase "concatOuter_1" concatOuter_1
+        , testCase "concatOuter_2" concatOuter_2
+        , testCase "window_1" window_1
+        , testCase "window_2" window_2
+        , testCase "window_3" window_3
+        , testCase "stride_1" stride_1
+        , testCase "stride_2" stride_2
+        , testCase "slice_1" slice_1
+        , testCase "slice_2" slice_2
+        , testCase "slice_3" slice_3
+        , testCase "slice_4" slice_4
+        , testCase "slice_5" slice_5
+        , testCase "rerank2_1" rerank2_1
+        , testCase "rev_1" rev_1
+        , testCase "rev_2" rev_2
+        , testCase "rev_3" rev_3
+        , testCase "reduce_1" reduce_1
+        , testCase "reduce_2" reduce_2
+        , testCase "reduce_3" reduce_3
+        ]
+  in  tests
diff --git a/tests/ShapedSTest.hs b/tests/ShapedSTest.hs
new file mode 100644
--- /dev/null
+++ b/tests/ShapedSTest.hs
@@ -0,0 +1,269 @@
+-- Copyright 2020 Google LLC
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--      http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module ShapedSTest(test) where
+
+import Control.DeepSeq
+import Control.Exception
+import Data.Array.ShapedS
+import qualified Data.Vector.Storable as V
+import Test.Framework (Test, testGroup)
+import Test.Framework.Providers.HUnit (testCase)
+import Test.HUnit (assertEqual, assertFailure, Assertion)
+
+assertThrows :: (NFData a) => String -> a -> Assertion
+assertThrows s a = catch (deepseq a $ assertFailure s) (\ (_ :: ErrorCall) -> return ())
+
+test :: Test
+test = testGroup "ShapedS" $
+  let a1, a1' :: Array [2,3] Int
+      a1 = fromList [1..6]
+      a1' = fromList [2..7]
+      a2 :: Array [3,2] Int
+      a2 = fromList [1,4,2,5,3,6]
+      show_1 = assertEqual "1" "fromList @[2,3] [1,2,3,4,5,6]" (show a1)
+      show_2 = assertEqual "2" "fromList @[3,2] [1,4,2,5,3,6]" (show a2)
+      eq_1 = assertEqual "1" True (a1 == a1)
+      eq_2 = assertEqual "2" False (a1 == a1')
+      ord_1 = assertEqual "1" EQ (a1 `compare` a1)
+      ord_2 = assertEqual "2" LT (a1 `compare` a1')
+      shapeL_1 = assertEqual "1" [2,3] (shapeL a1)
+      shapeL_2 = assertEqual "2" [3,2] (shapeL a2)
+      rank_1 = assertEqual "1" 2 (rank a1)
+      rank_2 = assertEqual "2" 2 (rank a2)
+      index_1 = assertEqual "1" (fromList [1,2,3]) (index a1 0)
+      index_2 = assertEqual "2" (fromList [1,4]) (index a2 0)
+      index_3 = assertEqual "3" (fromList [4]) (a2 `index` 0 `index` 1)
+      index_4 = assertThrows "<0" (index a1 (-1))
+      index_5 = assertThrows ">" (index a1 2)
+      toList_1 = assertEqual "1" [1,2,3,4,5,6] (toList a1)
+      toList_2 = assertEqual "2" [1,4,2,5,3,6] (toList a2)
+      toVector_1 = assertEqual "1" (V.fromList [1,2,3,4,5,6]) (toVector a1)
+      toVector_2 = assertEqual "2" (V.fromList [1,4,2,5,3,6]) (toVector a2)
+      fromList_1 = assertThrows "sh" (fromList [1,2] :: Array '[] Int)
+      fromList_2 = assertThrows "sh" (fromList [1,2] :: Array [4,5] Int)
+      fromVector_1 = assertEqual "1" a1 (fromVector $ V.fromList [1..6])
+      normalize_1 = assertEqual "1" a1 (normalize a1)
+      reshape_1 = assertEqual "1" (fromList [1..6] :: Array '[6] Int) (reshape a1)
+      reshape_2 = assertEqual "1" (fromList [1,4,2,5,3,6]) (reshape a2 :: Array [1,2,3,1] Int)
+      a3 :: Array '[1] Int
+      a3 = fromList [5]
+      a4 :: Array '[] Int
+      a4 = fromList [5]
+      stretch_1 = assertEqual "1" (fromList @'[3] [5,5,5]) (stretch @'[3] a3)
+      stretch_2 = assertEqual "2" (fromList @[2,2,3,2] [1,1,2,2,3,3,4,4,5,5,6,6,1,1,2,2,3,3,4,4,5,5,6,6])
+                                  (stretch @[2,2,3,2] (reshape @[1,2,3,1] a1))
+
+      scalar_1 = assertEqual "1" a4 (scalar 5)
+      unScalar_1 = assertEqual "1" 5 (unScalar a4)
+      constant_1 = assertEqual "1" (fromList [1,1,1,1,1,1]) (constant 1 :: Array [2,3] Int)
+      mapA_1 = assertEqual "1" (fromList [2..7]) (mapA succ a1)
+      mapA_2 = assertEqual "1" (fromList [2,5,3,6,4,7]) (mapA succ a2)
+      zipWithA_1 = assertEqual "1" (fromList [2,4..12]) (zipWithA (+) a1 a1)
+      zipWith3A_1 = assertEqual "1" (fromList [2,6,12,20,30,42]) (zipWith3A (\ x y z -> x*y+z) a1 a1 a1)
+      pad_1 = assertEqual "1" (fromList [9,9,9,9,9,9,9,9,9,9,
+                                         9,9,9,1,2,3,9,9,9,9,
+                                         9,9,9,4,5,6,9,9,9,9,
+                                         9,9,9,9,9,9,9,9,9,9,
+                                         9,9,9,9,9,9,9,9,9,9])
+                              (pad @['(1,2), '(3,4)] 9 a1)
+      a5 :: Array '[2,3,4] Int
+      a5 = fromList [1..24]
+      transpose_1 = assertEqual "1" (fromList [1,2,3,4,
+                                               5,6,7,8,
+                                               9,10,11,12,
+
+                                               13,14,15,16,
+                                               17,18,19,20,
+                                               21,22,23,24])
+                                    (transpose @'[0,1,2] a5)
+      transpose_2 = assertEqual "2" (fromList [1,5,9,
+                                               2,6,10,
+                                               3,7,11,
+                                               4,8,12,
+
+                                               13,17,21,
+                                               14,18,22,
+                                               15,19,23,
+                                               16,20,24])
+                                    (transpose @'[0,2,1] a5)
+      transpose_3 = assertEqual "3" (fromList [1,2,3,4,
+                                               13,14,15,16,
+
+                                               5,6,7,8,
+                                               17,18,19,20,
+
+                                               9,10,11,12,
+                                               21,22,23,24])
+                                    (transpose @'[1,0,2] a5)
+      transpose_4 = assertEqual "4" (fromList [1,13,
+                                               2,14,
+                                               3,15,
+                                               4,16,
+
+                                               5,17,
+                                               6,18,
+                                               7,19,
+                                               8,20,
+
+                                               9,21,
+                                               10,22,
+                                               11,23,
+                                               12,24])
+                                    (transpose @'[1,2,0] a5)
+      transpose_5 = assertEqual "5" (fromList [1,5,9,
+                                               13,17,21,
+
+                                               2,6,10,
+
+                                               14,18,22,
+
+                                               3,7,11,
+                                               15,19,23,
+
+                                               4,8,12,
+                                               16,20,24])
+                                    (transpose @'[2,0,1] a5)
+      transpose_6 = assertEqual "6" (fromList [1,13,
+                                               5,17,
+                                               9,21,
+
+                                               2,14,
+                                               6,18,
+                                               10,22,
+
+                                               3,15,
+                                               7,19,
+                                               11,23,
+
+                                               4,16,
+                                               8,20,
+                                               12,24])
+                                    (transpose @'[2,1,0] a5)
+      transpose_9 = assertEqual "9" (fromList [1,2,3,4,
+                                               13,14,15,16,
+
+                                               5,6,7,8,
+                                               17,18,19,20,
+
+                                               9,10,11,12,
+                                               21,22,23,24])
+                                    (transpose @'[1,0] a5)
+      append_1 = assertEqual "1" (fromList [1..9])
+                                 (append a1 (fromList @[1,3] [7,8,9]))
+      a6 :: Array [4,5] Int
+      a6 = fromList [1..20]
+      window_1 = assertEqual "1" (fromList @[2,3,3,3] [1,2,3,
+                                                      6,7,8,
+                                                      11,12,13,
+
+                                                      2,3,4,
+                                                      7,8,9,
+                                                      12,13,14,
+
+                                                      3,4,5,
+                                                      8,9,10,
+                                                      13,14,15,
+
+
+                                                      6,7,8,
+                                                      11,12,13,
+                                                      16,17,18,
+
+                                                      7,8,9,
+                                                      12,13,14,
+                                                      17,18,19,
+
+                                                      8,9,10,
+                                                      13,14,15,
+                                                      18,19,20])
+                                 (window @[3,3] a6)
+      stride_1 = assertEqual "1" (fromList @[2,2,2] [1,3,
+                                                    9,11,
+
+                                                    13,15,
+                                                    21,23])
+                                 (stride @[1,2,2] a5)
+      slice_1 = assertEqual "1" (fromList @[2,2,1] [8,12,20,24])
+                                (slice @['(0,2), '(1,2), '(3,1)] a5)
+      a7 = mapA succ a5
+      dot x y = reduce (+) 0 $ zipWithA (*) x y
+      rerank2_1 = assertEqual "1" (fromList [40,200,488,904,1448,2120])
+                                  (rerank2 @2 dot a5 a7)
+      rev_1 = assertEqual "1" (fromList [3,2,1,6,5,4])
+                              (rev @'[1] a1)
+      rev_2 = assertEqual "2" (fromList [6,5,4,3,2,1])
+                              (rev @[0,1] a1)
+      reduce_1 = assertEqual "1" (scalar 720) (reduce (*) 1 a1)
+      reduce_2 = assertEqual "2" (fromList @'[2] [6,120]) (rerank @1 (reduce (*) 1) a1)
+      reduce_3 = assertEqual "3" (fromList @'[3] [4,10,18]) (rerank @1 (reduce (*) 1) a2)
+
+      tests =
+        [ testCase "show_1" show_1
+        , testCase "show_2" show_2
+        , testCase "eq_1" eq_1
+        , testCase "eq_2" eq_2
+        , testCase "ord_1" ord_1
+        , testCase "ord_2" ord_2
+        , testCase "shapeL_1" shapeL_1
+        , testCase "shapeL_2" shapeL_2
+        , testCase "rank_1" rank_1
+        , testCase "rank_2" rank_2
+        , testCase "index_1" index_1
+        , testCase "index_2" index_2
+        , testCase "index_3" index_3
+        , testCase "index_4" index_4
+        , testCase "index_5" index_5
+        , testCase "toList_1" toList_1
+        , testCase "toList_2" toList_2
+        , testCase "toVector_1" toVector_1
+        , testCase "toVector_2" toVector_2
+        , testCase "fromList_1" fromList_1
+        , testCase "fromList_2" fromList_2
+        , testCase "fromVector_1" fromVector_1
+        , testCase "normalize_1" normalize_1
+        , testCase "reshape_1" reshape_1
+        , testCase "reshape_2" reshape_2
+        , testCase "stretch_1" stretch_1
+        , testCase "stretch_2" stretch_2
+        , testCase "scalar_1" scalar_1
+        , testCase "unScalar_1" unScalar_1
+        , testCase "constant_1" constant_1
+        , testCase "mapA_1" mapA_1
+        , testCase "mapA_2" mapA_2
+        , testCase "zipWithA_1" zipWithA_1
+        , testCase "zipWith3A_1" zipWith3A_1
+        , testCase "pad_1" pad_1
+        , testCase "transpose_1" transpose_1
+        , testCase "transpose_2" transpose_2
+        , testCase "transpose_3" transpose_3
+        , testCase "transpose_4" transpose_4
+        , testCase "transpose_5" transpose_5
+        , testCase "transpose_6" transpose_6
+        , testCase "transpose_9" transpose_9
+        , testCase "append_1" append_1
+        , testCase "window_1" window_1
+        , testCase "stride_1" stride_1
+        , testCase "slice_1" slice_1
+        , testCase "rerank2_1" rerank2_1
+        , testCase "rev_1" rev_1
+        , testCase "rev_2" rev_2
+        , testCase "reduce_1" reduce_1
+        , testCase "reduce_2" reduce_2
+        , testCase "reduce_3" reduce_3
+        ]
+  in  tests
