diff --git a/Foreign/Marshal/StaticArray.hs b/Foreign/Marshal/StaticArray.hs
--- a/Foreign/Marshal/StaticArray.hs
+++ b/Foreign/Marshal/StaticArray.hs
@@ -1,8 +1,8 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE RecursiveDo #-}
@@ -20,7 +20,7 @@
 Multidimensional native arrays are also supported. @'StaticArray'
 'UArray' \'(10,20,100) CUChar@ is compatible with @unsigned char
 foo[10][20][100]@. Note the leading @\'@ before the tuple containing
-the dimensions. It marks it as a @DataKinds@ lifted tuple, necessary
+the dimensions. It marks it as a @DataKinds@ promoted tuple, necessary
 to store the dimensions.
 
 To operate on the contents of a 'StaticArray', use
@@ -32,11 +32,11 @@
 
 -}
 module Foreign.Marshal.StaticArray
-       ( Mutable
-       , StaticArray
+       ( StaticArray
+       , Mutable
+       , toArray
        , staticArray
        , listStaticArray
-       , toArray
        , StaticSize(..)
        , fromNat
        ) where
@@ -62,18 +62,23 @@
 --
 -- The constructor is not exported to prevent creating a StaticArray
 -- with a size that doesn't match its dimensions.
-newtype StaticArray backing dimensions elements =
+newtype StaticArray backing dimensions (elements :: *) =
     StaticArray {
         -- | Returns the backing 'Array' of this 'StaticArray'.
         toArray :: backing (Bound dimensions) elements
         }
-    deriving (Eq, Show)
+    deriving Eq
 
+instance (IArray b e, Ix (Bound d), Show e) => Show (StaticArray b d e) where
+    show = ("listStaticArray " ++) . show . elems . toArray
+
 -- | This class connects dimension description types with 'IArray'
--- index types and values. Instances are provided for up to 13
--- dimensions as tuples. Additionally, there is support for unlimited
--- dimensions via a list of dimensions. This results in nested pairs
--- for the index type.
+-- index types and values.
+--
+-- This module contains instances for types of kind 'Nat', types of
+-- the promoted kind \'['Nat'], and promoted tuples of 'Nat' values up
+-- to 13 elements. For instances not relying on promoted data types,
+-- see the "Foreign.Marshal.StaticArray.Unpromoted" module.
 class StaticSize d where
     -- | The bounding type for this dimension description
     type Bound d :: *
@@ -102,9 +107,9 @@
 -- 'unsafeFreeze'. This is used to increase the efficiency of 'peek'
 -- in 'StaticArray' 's 'Storable' instance.
 --
--- If you're somehow using an instance of 'IArray' other than 'Array'
--- or 'UArray', you'll need to add a type instance for your type. If
--- it supports non-copying 'unsafeFreeze', the type instance should
+-- If you're using an instance of 'IArray' other than 'Array' or
+-- 'UArray', you'll need to add a type instance for your type. If it
+-- supports non-copying 'unsafeFreeze', the type instance should
 -- return the type constructor for the appropriate 'MArray'
 -- instance. Otherwise, just have it return 'IOArray'
 type family Mutable (a :: * -> * -> *) :: * -> * -> *
@@ -149,10 +154,17 @@
 fromNat :: forall (proxy :: Nat -> *) (n :: Nat). SingI n => proxy n -> Int
 fromNat _ = fromInteger $ fromSing (sing :: Sing n)
 
-----------------------------------------------------------------------------
--- StaticSize instances. More can be written, trivially - it's just a matter
--- of whether they'll ever actually be used.
+instance SingI n => StaticSize ('[n] :: [Nat]) where
+    type Bound ('[n]) = Int
+    extent _ = (0, fromNat (Proxy :: Proxy n) - 1)
 
+instance (SingI n, StaticSize (n2 ': ns)) =>
+          StaticSize ((n ': n2 ': ns) :: [Nat]) where
+    type Bound (n ': n2 ': ns) = (Int, Bound (n2 ': ns))
+    extent _ = ((0, b0), (fromNat (Proxy :: Proxy n) - 1, bn))
+      where
+        (b0, bn) = extent (undefined :: StaticArray a (n2 ': ns) b)
+
 instance SingI a => StaticSize (a :: Nat) where
     type Bound a = Int
     extent _ = (0, fromNat (Proxy :: Proxy a) - 1)
@@ -328,14 +340,3 @@
                  fromNat (Proxy :: Proxy k) - 1,
                  fromNat (Proxy :: Proxy l) - 1,
                  fromNat (Proxy :: Proxy m) - 1))
-
-instance SingI n => StaticSize ('[n] :: [Nat]) where
-    type Bound ('[n]) = Int
-    extent _ = (0, fromNat (Proxy :: Proxy n) - 1)
-
-instance (SingI n, StaticSize (n2 ': ns)) =>
-          StaticSize ((n ': n2 ': ns) :: [Nat]) where
-    type Bound (n ': n2 ': ns) = (Int, Bound (n2 ': ns))
-    extent _ = ((0, b0), (fromNat (Proxy :: Proxy n) - 1, bn))
-      where
-        (b0, bn) = extent (undefined :: StaticArray a (n2 ': ns) ())
diff --git a/Foreign/Marshal/StaticArray/Unpromoted.hs b/Foreign/Marshal/StaticArray/Unpromoted.hs
new file mode 100644
--- /dev/null
+++ b/Foreign/Marshal/StaticArray/Unpromoted.hs
@@ -0,0 +1,273 @@
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE EmptyDataDecls #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-|
+
+This module contains a collection of data types for describing
+dimensions of 'StaticArray' that do not depend on promoted lists and
+tuples.
+
+For convenience, it re-exports all of "Foreign.Marshal.StaticArray".
+
+-}
+module Foreign.Marshal.StaticArray.Unpromoted
+       ( module Foreign.Marshal.StaticArray
+       , (:.)
+       , Nil
+       , D2
+       , D3
+       , D4
+       , D5
+       , D6
+       , D7
+       , D8
+       , D9
+       , D10
+       , D11
+       , D12
+       , D13
+       ) where
+
+import Data.Proxy
+
+import GHC.TypeLits
+
+import Foreign.Marshal.StaticArray
+
+-- | ':.' is provided as an alternative means of constructing a
+-- type-level list of dimensions. @DataKinds@-promoted lists are also
+-- supported and easier to use in almost all cases. The exception is
+-- when @CPP@ is involved, when a single @'@ on a line causes @CPP@ to
+-- fail.
+--
+-- With @TypeOperators@ and @DataKinds@ enabled, @'StaticArray'
+-- 'UArray' (2:.10:.25:.'Nil') 'Int'@ is equivalent to @'StaticArray'
+-- 'UArray' \'[2,10,25] 'Int'@ and both wrap a @'UArray'
+-- ('Int',('Int','Int')) 'Int'@ with bounds @((0,(0,0)),(1,(9,24)))@.
+--
+-- Neither promoted lists nor this approach support creating
+-- 0-dimensional arrays, because they make no sense with 'Storable'.
+data a :. b
+
+-- | 'Nil' is the terminator for type-level lists created with ':.'
+data Nil
+
+infixr 3 :.
+
+instance SingI n => StaticSize ((n :: Nat) :. Nil) where
+    type Bound (n :. Nil) = Int
+    extent _ = (0, fromNat (Proxy :: Proxy n) - 1)
+
+instance (SingI n, StaticSize (n2 :. ns)) =>
+          StaticSize ((n :: Nat) :. n2 :. ns) where
+    type Bound (n :. n2 :. ns) = (Int, Bound (n2 :. ns))
+    extent _ = ((0, b0), (fromNat (Proxy :: Proxy n) - 1, bn))
+      where
+        (b0, bn) = extent (undefined :: StaticArray a (n2 :. ns) b)
+
+-- | An alternative dimension type to promoted pairs, provided for
+-- syntactic compatibility with @CPP@.
+data D2 (a :: Nat) (b :: Nat)
+instance (SingI a, SingI b) => StaticSize (D2 a b) where
+    type Bound (D2 a b) = (Int, Int)
+    extent _ = ((0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1))
+
+-- | An alternative dimension type to promoted triples, provided for
+-- syntactic compatibility with @CPP@.
+data D3 (a :: Nat) (b :: Nat) (c :: Nat)
+instance (SingI a, SingI b, SingI c) => StaticSize (D3 a b c) where
+    type Bound (D3 a b c) = (Int, Int, Int)
+    extent _ = ((0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1))
+
+-- | An alternative dimension type to promoted 4-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D4 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d) => StaticSize (D4 a b c d) where
+    type Bound (D4 a b c d) = (Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1))
+
+-- | An alternative dimension type to promoted 5-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D5 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat) (e :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d, SingI e) =>
+         StaticSize (D5 a b c d e) where
+    type Bound (D5 a b c d e) = (Int, Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1,
+                 fromNat (Proxy :: Proxy e) - 1))
+
+-- | An alternative dimension type to promoted 6-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D6 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat) (e :: Nat) (f :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d, SingI e, SingI f) =>
+         StaticSize (D6 a b c d e f) where
+    type Bound (D6 a b c d e f) = (Int, Int, Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1,
+                 fromNat (Proxy :: Proxy e) - 1,
+                 fromNat (Proxy :: Proxy f) - 1))
+
+-- | An alternative dimension type to promoted 7-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D7 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat) (e :: Nat) (f :: Nat)
+     (g :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d, SingI e, SingI f, SingI g) =>
+         StaticSize (D7 a b c d e f g) where
+    type Bound (D7 a b c d e f g) = (Int, Int, Int, Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1,
+                 fromNat (Proxy :: Proxy e) - 1,
+                 fromNat (Proxy :: Proxy f) - 1,
+                 fromNat (Proxy :: Proxy g) - 1))
+
+-- | An alternative dimension type to promoted 8-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D8 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat) (e :: Nat) (f :: Nat)
+     (g :: Nat) (h :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d, SingI e, SingI f, SingI g,
+          SingI h) =>
+         StaticSize (D8 a b c d e f g h) where
+    type Bound (D8 a b c d e f g h) = (Int, Int, Int, Int, Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0, 0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1,
+                 fromNat (Proxy :: Proxy e) - 1,
+                 fromNat (Proxy :: Proxy f) - 1,
+                 fromNat (Proxy :: Proxy g) - 1,
+                 fromNat (Proxy :: Proxy h) - 1))
+
+-- | An alternative dimension type to promoted 9-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D9 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat) (e :: Nat) (f :: Nat)
+     (g :: Nat) (h :: Nat) (i :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d, SingI e, SingI f, SingI g,
+          SingI h, SingI i) =>
+         StaticSize (D9 a b c d e f g h i) where
+    type Bound (D9 a b c d e f g h i) =
+        (Int, Int, Int, Int, Int, Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0, 0, 0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1,
+                 fromNat (Proxy :: Proxy e) - 1,
+                 fromNat (Proxy :: Proxy f) - 1,
+                 fromNat (Proxy :: Proxy g) - 1,
+                 fromNat (Proxy :: Proxy h) - 1,
+                 fromNat (Proxy :: Proxy i) - 1))
+
+-- | An alternative dimension type to promoted 10-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D10 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat) (e :: Nat) (f :: Nat)
+     (g :: Nat) (h :: Nat) (i :: Nat) (j :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d, SingI e, SingI f, SingI g,
+          SingI h, SingI i, SingI j) =>
+         StaticSize (D10 a b c d e f g h i j) where
+    type Bound (D10 a b c d e f g h i j) =
+        (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1,
+                 fromNat (Proxy :: Proxy e) - 1,
+                 fromNat (Proxy :: Proxy f) - 1,
+                 fromNat (Proxy :: Proxy g) - 1,
+                 fromNat (Proxy :: Proxy h) - 1,
+                 fromNat (Proxy :: Proxy i) - 1,
+                 fromNat (Proxy :: Proxy j) - 1))
+
+-- | An alternative dimension type to promoted 11-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D11 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat) (e :: Nat) (f :: Nat)
+     (g :: Nat) (h :: Nat) (i :: Nat) (j :: Nat) (k :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d, SingI e, SingI f, SingI g,
+          SingI h, SingI i, SingI j, SingI k) =>
+         StaticSize (D11 a b c d e f g h i j k) where
+    type Bound (D11 a b c d e f g h i j k) =
+        (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1,
+                 fromNat (Proxy :: Proxy e) - 1,
+                 fromNat (Proxy :: Proxy f) - 1,
+                 fromNat (Proxy :: Proxy g) - 1,
+                 fromNat (Proxy :: Proxy h) - 1,
+                 fromNat (Proxy :: Proxy i) - 1,
+                 fromNat (Proxy :: Proxy j) - 1,
+                 fromNat (Proxy :: Proxy k) - 1))
+
+-- | An alternative dimension type to promoted 12-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D12 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat) (e :: Nat) (f :: Nat)
+     (g :: Nat) (h :: Nat) (i :: Nat) (j :: Nat) (k :: Nat) (l :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d, SingI e, SingI f, SingI g,
+          SingI h, SingI i, SingI j, SingI k, SingI l) =>
+         StaticSize (D12 a b c d e f g h i j k l) where
+    type Bound (D12 a b c d e f g h i j k l) =
+        (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1,
+                 fromNat (Proxy :: Proxy e) - 1,
+                 fromNat (Proxy :: Proxy f) - 1,
+                 fromNat (Proxy :: Proxy g) - 1,
+                 fromNat (Proxy :: Proxy h) - 1,
+                 fromNat (Proxy :: Proxy i) - 1,
+                 fromNat (Proxy :: Proxy j) - 1,
+                 fromNat (Proxy :: Proxy k) - 1,
+                 fromNat (Proxy :: Proxy l) - 1))
+
+-- | An alternative dimension type to promoted 13-tuples, provided for
+-- syntactic compatibility with @CPP@.
+data D13 (a :: Nat) (b :: Nat) (c :: Nat) (d :: Nat) (e :: Nat) (f :: Nat)
+     (g :: Nat) (h :: Nat) (i :: Nat) (j :: Nat) (k :: Nat) (l :: Nat)
+     (m :: Nat)
+instance (SingI a, SingI b, SingI c, SingI d, SingI e, SingI f, SingI g,
+          SingI h, SingI i, SingI j, SingI k, SingI l, SingI m) =>
+         StaticSize (D13 a b c d e f g h i j k l m) where
+    type Bound (D13 a b c d e f g h i j k l m) =
+        (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)
+    extent _ = ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+                (fromNat (Proxy :: Proxy a) - 1,
+                 fromNat (Proxy :: Proxy b) - 1,
+                 fromNat (Proxy :: Proxy c) - 1,
+                 fromNat (Proxy :: Proxy d) - 1,
+                 fromNat (Proxy :: Proxy e) - 1,
+                 fromNat (Proxy :: Proxy f) - 1,
+                 fromNat (Proxy :: Proxy g) - 1,
+                 fromNat (Proxy :: Proxy h) - 1,
+                 fromNat (Proxy :: Proxy i) - 1,
+                 fromNat (Proxy :: Proxy j) - 1,
+                 fromNat (Proxy :: Proxy k) - 1,
+                 fromNat (Proxy :: Proxy l) - 1,
+                 fromNat (Proxy :: Proxy m) - 1))
diff --git a/storable-static-array.cabal b/storable-static-array.cabal
--- a/storable-static-array.cabal
+++ b/storable-static-array.cabal
@@ -1,5 +1,5 @@
 name:                storable-static-array
-version:             0.4.0.1
+version:             0.4.1.0
 synopsis:            Statically-sized array wrappers with Storable instances
                      for FFI marshaling
 description:         Uses type-level numeric literals to wrap arrays in a type
@@ -20,6 +20,7 @@
   location:          https://github.com/chowells79/storable-static-array.git
 
 library
-  exposed-modules:   Foreign.Marshal.StaticArray
+  exposed-modules:   Foreign.Marshal.StaticArray,
+                     Foreign.Marshal.StaticArray.Unpromoted
   build-depends:     base ==4.6.*, array ==0.4.*, tagged ==0.6.*
   ghc-options:       -Wall
