{-# LANGUAGE DataKinds, GADTs, TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE ExplicitForAll  #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE NoImplicitPrelude #-}


module Numerical.Array.Shape(
  -- * Shape
    Shape(..)
    -- * Shape Utilities
    ,foldl
    ,foldr
    ,foldl'
    ,foldl1
    ,foldr1
    ,map
    ,map2
    ,reverseShape
    ,Nat(..)
    ,shapeSize
    ,SNat(..)
    ,weaklyDominates
    ,strictlyDominates
    ,shapeToList
    ,Index
    ,backwards
    -- * Unboxed Vector Morphism
    ,UnBoxedShapeMorphism(..)
    ,unShapeVector
    ,reShapeVector
    ,T.traverse
    --,T.Traversable(..)

    )
    where

--import Data.Data
import Data.Typeable
import Data.Data

import qualified Data.Functor as Fun
import qualified  Data.Foldable as F
import qualified Control.Applicative as A
import Control.Monad (liftM)
import Control.Monad.ST (runST)
import qualified Data.Traversable as T

--import Control.NumericalMonad.State.Strict
import Control.NumericalApplicative.Backwards


import Numerical.Nat
import qualified Data.Monoid as Monoid

import Prelude hiding  (map,foldl,foldr,init,scanl,scanr,scanl1,scanr1,foldl1,foldr1)

import qualified Foreign.Storable  as Store
import qualified Foreign.Ptr as Ptr

import qualified Data.Vector.Unboxed as UV
import  qualified  Data.Vector.Unboxed.Mutable as UVM
import qualified Data.Vector.Generic as GV
import qualified Data.Vector.Generic.Mutable as GMV

{-
Shape may get renamed to Index in the near future!

PSA: do not take the INLINE pragmas as a style suggestion.
The only reason for the INLINEs, SPECIALIZE and the
nonrecursive type class definitions of operations
in this module are because shape will be used in the inner loops of
array indexing heavy computations,

-}


 {-
the concern basically boils down to "will it specialize / inline well"

 -}


{-
should explore using the Reverse and Backwards transformers in the
Transformers package, but not right now

note also the *Tup operations could be done with a more general State monad
for the tupled accumulation parameter. If theres no perf regression, should
move to using that instead.

-}


infixr 3 :*

type Index rank = Shape rank Int

data Shape (rank :: Nat) a where
    Nil  :: Shape 'Z a
    (:*) ::  !(a) -> !(Shape r a ) -> Shape  ('S r) a


deriving instance Typeable Shape


nilShapeConstrRep :: Constr
nilShapeConstrRep    = mkConstr shapeDataTypeRep "Nil" [] Prefix
consShapeConstrRep :: Constr
consShapeConstrRep   = mkConstr shapeDataTypeRep ":*" [] Infix

shapeDataTypeRep :: DataType
shapeDataTypeRep = mkDataType "Numerical.Array.Shape.Shape" [nilShapeConstrRep,consShapeConstrRep]


--deriving instance (Data a, Typeable n ) => Data (Shape n a)
--  gfoldl f z xs = gfoldl f z (shapeToList xs)

--  --gfoldl _ z Nil = z Nil
--  --gfoldl f z (x :* xs) = z (:*)  `f`  x `f` xs

-- I would like to have (Data (Shape n a)) but that seems tricky

instance (Data a,Typeable 'Z) =>  Data (Shape 'Z a) where
    gfoldl _ z Nil = z Nil
    gunfold _ z _  = z Nil -- not sure if _ z _ is the right one, but typechecks
    dataTypeOf _  = shapeDataTypeRep
    toConstr _ = nilShapeConstrRep

instance (Data a, Data (Shape n a), Typeable ('S n))=> Data (Shape ('S n) a ) where
    gfoldl k z (a :* b) = (z (:*) `k` a) `k` b
    gunfold k z _ = k (k (z (:*)))
    dataTypeOf _ = shapeDataTypeRep
    toConstr _   = consShapeConstrRep


-- figure this out!
--look at  http://hackage.haskell.org/package/HList-0.3.4.1/docs/src/Data-HList-Data.html
--and https://hackage.haskell.org/package/base-4.3.1.0/docs/Data-Data.html#nilConstr
-- for examples
--instance Data a => Data (Shape Z a) where
  --gfoldl

--deriving instance Data (Shape Z a)
--deriving instance (Data a,Data (Shape n a))=> (Data (Shape (S n) a))

{-
too much work to do data instance with pre 7.8 typeable
-}



instance  Eq (Shape 'Z a) where
    (==) _ _ = True
    {-#INLINE (==)#-}
instance (Eq a,Eq (Shape s a))=> Eq (Shape ('S s) a )  where
    (==)  (a:* as) (b:* bs) =  (a == b) && (as == bs )
    {-#INLINE (==)#-}
instance  Show (Shape 'Z a) where
    show _ = "Nil"

instance (Show a, Show (Shape s a))=> Show (Shape ('S s) a) where
    show (a:* as) = show a  ++ " :* " ++ show as

-- at some point also try data model that
-- has layout be dynamically reified, but for now
-- keep it phantom typed for sanity / forcing static dispatch.
-- NB: may need to make it more general at some future point
--data Strided r a lay = Strided {   getStrides :: Shape r a   }

-- may want to typeclassify this?


shapeToList :: Shape n a -> [a]
shapeToList Nil = []
shapeToList (a:* as) = a : (shapeToList as )


{-
the Traversable instance for shape needs both Z and S Z base
cases to interact nicely with the instances defined for
foldable
-}

instance T.Traversable (Shape 'Z) where
  traverse = \ _ Nil -> A.pure Nil
  {-# INLINE traverse #-}
  sequenceA = T.traverse id
  mapM f = A.unwrapMonad . T.traverse (A.WrapMonad . f)
  sequence = T.mapM id
  {-#INLINE sequenceA #-}
  {-#INLINE mapM #-}
  {-#INLINE sequence #-}


instance  T.Traversable (Shape ('S 'Z)) where
  traverse = \ f (a:* as) ->  (:*) A.<$> f a A.<*> T.traverse f as
  {-# INLINE traverse #-}
  sequenceA = T.traverse id
  mapM f = A.unwrapMonad . T.traverse (A.WrapMonad . f)
  sequence = T.mapM id
  {-#INLINE sequenceA #-}
  {-#INLINE mapM #-}
  {-#INLINE sequence #-}

instance T.Traversable (Shape ('S n)) => T.Traversable (Shape ('S ('S n))) where
  traverse = \ f (a:* as) ->  (:*) A.<$> f a A.<*> T.traverse f as
  {-#INLINE traverse #-}
  sequenceA = T.traverse id
  mapM f = A.unwrapMonad . T.traverse (A.WrapMonad . f)
  sequence = T.mapM id
  {-#INLINE sequenceA #-}
  {-#INLINE mapM #-}
  {-#INLINE sequence #-}

backwards :: (T.Traversable t, A.Applicative f) =>
      ((a -> Backwards f b) -> t a -> Backwards f (t b))
        -> ((a -> f b) -> t a -> f (t b))
backwards= \ traver f container ->
    forwards $ traver  (\x -> Backwards $ f x) container
{-#INLINE backwards #-}




--instance Fun.Functor (Shape r) where
--    fmap = mapShape
--    {-#INLINE fmap #-}

instance Fun.Functor (Shape 'Z) where
    fmap  = \ _ Nil -> Nil
    {-# INLINE  fmap #-}

instance  (Fun.Functor (Shape r)) => Fun.Functor (Shape ('S r)) where
    fmap  = \ f (a :* rest) -> f a :* ( Fun.fmap f rest )
    {-# INLINE  fmap  #-}

instance  A.Applicative (Shape 'Z) where
    pure = \ _ -> Nil
    {-# INLINE  pure  #-}
    (<*>) = \ _  _ -> Nil
    {-# INLINE  (<*>) #-}

instance  A.Applicative (Shape r)=> A.Applicative (Shape ('S r)) where
    pure = \ a -> a :* (A.pure a)
    {-# INLINE pure #-}
    (<*>) = \ (f:* fs) (a :* as) ->  f a :* ((A.<*>)) fs as
    {-# INLINE  (<*>) #-}

{-
only doing Foldable for ranks >= 1 does mean that
we dont get the cute "rank zero arrays are references"
property. But want foldr1 and foldl1 to always succeed

lets try having rank 0 anyways, i'll be happier if i can support it

-}

instance    F.Foldable (Shape  'Z) where
    foldl' = \ _  !init _->  init
    foldr'  = \ _ !init _ ->  init
    foldl  = \ _ init _->  init
    foldr  = \ _ init _->   init
    foldMap = \ _f _col -> mempty
    {-# INLINE foldMap  #-}
    {-#  INLINE foldl #-}
    {-#  INLINE foldr  #-}
    {-# INLINE foldl' #-}
    {-#  INLINE foldr'  #-}
    foldr1 = \ _ _ -> error "you can't call foldr1 on a rank Z(ero) Shape"
    foldl1 =  \_ _  ->  error "you can't call foldl1 on a rank Z(ero) Shape"


instance    F.Foldable (Shape  ('S 'Z)) where
    foldl' = \ f !init (a:*Nil)->  f init a
    foldr'  = \ f !init (a:*Nil)->  f a init
    foldl  = \ f init (a:*Nil)->  f init a
    foldr  = \ f init (a:*Nil)->  f a init
    foldMap = \ f (a :* Nil ) -> f a
    {-# INLINE foldMap  #-}
    {-#  INLINE foldl #-}
    {-#  INLINE foldr  #-}
    {-# INLINE foldl' #-}
    {-#  INLINE foldr'  #-}
    foldr1 = \ _ (a:* Nil) -> a
    foldl1 =  \ _ (a:* Nil) -> a
    {-#  INLINE foldl1 #-}
    {-#  INLINE foldr1 #-}
instance ( F.Foldable (Shape ('S r)) )=> F.Foldable (Shape ('S ('S r))) where
    foldl' = \ f  init (a:* as) -> F.foldl' f (f init a) as
    foldr' = \f !init (a :* as ) -> f a $!  F.foldr' f init as
    foldl  = \ f  init (a:* as) -> F.foldl' f (f init a) as
    foldr  = \ f  init (a:* as) ->   f a $!  F.foldr f init as
    foldl1 = \ f (a:* as) -> F.foldl' f a as
    foldr1 = \ f (a :* as) -> F.foldr' f a as
    foldMap = \ f (a :* as ) -> f a Monoid.<> F.foldMap f as
    {-# INLINE foldMap  #-}
    {-# INLINE foldl #-}
    {-# INLINE foldr  #-}
    {-# INLINE foldl' #-}
    {-# INLINE foldr'  #-}
    {-# INLINE foldl1 #-}
    {-# INLINE foldr1 #-}

instance (Semigroup a, A.Applicative (Shape n))=> (Semigroup (Shape n a)) where
  (<>) = \ a b -> A.pure (<>) A.<*> a A.<*> b

instance (Monoid.Monoid a, A.Applicative (Shape n))=> Monoid.Monoid (Shape n a) where
  mempty = A.pure Monoid.mempty
  mappend = \ a b -> A.pure Monoid.mappend A.<*> a A.<*> b




{- when you lift a toral order onto vectors, you get
interesting partial order -}

-- | 'weaklyDominates' is the '<=' operator lifted onto  a sized vector to
-- induce a partial order relation
weaklyDominates :: (Ord a, A.Applicative  (Shape n), F.Foldable (Shape n) )=>
                        Shape n a -> Shape n a -> Bool
weaklyDominates = \major minor -> foldl (&&) True $! map2 (>=)  major minor
{-# INLINE weaklyDominates #-}

-- | 'strictlyDominates' is the '<' operator lifted onto  a sized vector to
-- induce a partial order relation
strictlyDominates :: (Ord a, A.Applicative  (Shape n), F.Foldable (Shape n) )=>
                        Shape n a -> Shape n a -> Bool

strictlyDominates  = \major minor -> foldl (&&) True $! map2 (>)  major minor
{-# INLINE strictlyDominates #-}

{-# INLINE reverseShape #-}
reverseShape :: Shape n a -> Shape n a
reverseShape Nil = Nil
reverseShape r@(_ :* Nil)= r
reverseShape (a:* b :* Nil) = b:* a :* Nil
reverseShape (a:* b :* c:* Nil )=  c :* b :* a :* Nil
reverseShape (a:* b :* c :* d :* Nil)= d :* c :* b :* a :* Nil
reverseShape list = go SZero Nil list
  where
    go :: SNat n1 -> Shape n1  a-> Shape n2 a -> Shape (n1 + n2) a
    go snat acc Nil = gcastWith (plus_id_r snat) acc
    go snat acc (h :* (t :: Shape n3 a)) =
      gcastWith (plus_succ_r snat (Proxy :: Proxy n3))
              (go (SSucc snat) (h :* acc) t)


{-
TODO: abstract out all the different unrolled cases i have


-}




{-# INLINE map2 #-}
map2 :: forall a b c r . (A.Applicative (Shape r))=>   (a->b ->c) -> (Shape r a) -> (Shape r b) -> (Shape r c )
map2  = \ f shpa shpb -> f A.<$> shpa  A.<*> shpb


{-# INLINE map #-}
map:: forall a b r . (A.Applicative (Shape r))=> (a->b) -> (Shape r a )->( Shape r b)
map  =  \ f shp -> f A.<$> shp



{-# INLINE  foldr #-}
foldr :: forall a b r . (F.Foldable (Shape r))=>  (a->b-> b) -> b -> Shape r a -> b
foldr  = \ f init shp -> F.foldr  f init shp




{-# INLINE  foldl #-}
foldl :: forall a b r. (F.Foldable (Shape r))=> (b-> a -> b) -> b -> Shape r a -> b
foldl  = \ f init shp -> F.foldl f init shp


{-# INLINE foldl' #-}
foldl' :: forall a b r . (F.Foldable (Shape r))=> (b-> a -> b) -> b -> Shape r a -> b
foldl' = \ f init shp -> F.foldl' f init shp

{-# INLINE  foldr1 #-}
foldr1 :: forall b r . (F.Foldable (Shape ('S r)))=>  (b->b-> b)  -> Shape ('S r) b -> b
foldr1  = \ f  shp -> F.foldr1  f  shp




{-# INLINE  foldl1 #-}
foldl1 :: forall  b r. (F.Foldable (Shape ('S r)))=> (b-> b -> b)  -> Shape ('S r) b -> b
foldl1  = \ f  shp -> F.foldl1 f  shp





instance Store.Storable a =>Store.Storable (Shape ('S 'Z) a) where
    {-#INLINE sizeOf#-}
    sizeOf = \ _ ->  (Store.sizeOf (undefined :: a))
    -- might want to boost the alignment, but ignore for now
    {-# INLINE alignment #-}
    alignment = \ _ -> Store.alignment (undefined :: a )
    {-# INLINE peek #-}
    peek = \ptr -> do  res <- Store.peek (Ptr.castPtr ptr) ; return (res :* Nil)
    {-# INLINE poke #-}
    poke = \ptr (a:*_) -> Store.poke (Ptr.castPtr ptr) a
    {-# INLINE pokeElemOff #-}
    {-# INLINE peekElemOff #-}
    peekElemOff = \ ptr off -> Store.peekByteOff ptr (off * Store.sizeOf (undefined ::  a ))
    pokeElemOff ptr off val = Store.pokeByteOff ptr (off * Store.sizeOf val) val

    peekByteOff ptr off = Store.peek (ptr `Ptr.plusPtr` off)
    pokeByteOff ptr off = Store.poke (ptr `Ptr.plusPtr` off)
    {-# INLINE peekByteOff #-}
    {-# INLINE pokeByteOff #-}


instance (Store.Storable a,Store.Storable (Shape ('S n) a)) =>Store.Storable (Shape ('S ('S n)) a) where
    {-#INLINE sizeOf#-}
    sizeOf = \ _ ->  Store.sizeOf (undefined :: a)  + Store.sizeOf (undefined :: (Shape ('S n) a ))
    -- might want to boost the alignment, but ignore for now
    {-# INLINE alignment #-}
    alignment = \ _ -> Store.alignment (undefined :: a )
    {-# INLINE peek #-}
    peek = \ptr -> do
                a <- Store.peek (Ptr.castPtr ptr) ;
                as <- Store.peek (ptr `Ptr.plusPtr` Store.sizeOf (undefined :: a ))
                return (a:* as)
    {-# INLINE poke #-}
    poke = \ptr (a:*as ) -> do
                        Store.poke (Ptr.castPtr ptr) a
                        Store.poke (ptr `Ptr.plusPtr` Store.sizeOf (undefined :: a )) as
    {-# INLINE pokeElemOff #-}
    {-# INLINE peekElemOff #-}
    peekElemOff = \ ptr off -> Store.peekByteOff ptr (off * Store.sizeOf (undefined :: (Shape ('S ('S n)) a) ))
    pokeElemOff ptr off val = Store.pokeByteOff ptr (off * Store.sizeOf val) val

    peekByteOff ptr off = Store.peek (ptr `Ptr.plusPtr` off)
    pokeByteOff ptr off = Store.poke (ptr `Ptr.plusPtr` off)
    {-# INLINE peekByteOff #-}
    {-# INLINE pokeByteOff #-}

-- this instance is a bit weird and should never be used
-- but probably legal
instance Store.Storable a =>Store.Storable (Shape 'Z a) where
    {-#INLINE sizeOf#-}
    sizeOf = \ _ ->  Store.sizeOf (undefined :: a )
    -- might want to boost the alignment, but ignore for now
    {-# INLINE alignment #-}
    alignment = \ _ -> Store.alignment (undefined :: a )
    {-# INLINE peek #-}
    peek = \ _  -> return Nil
    {-# INLINE poke #-}
    poke = \ _  _-> return ()
    {-# INLINE pokeElemOff #-}
    {-# INLINE peekElemOff #-}
    peekElemOff = \ _ _  -> return Nil
    pokeElemOff = \ _ _ _  -> return ()

    peekByteOff  = \ _ _ -> return Nil
    pokeByteOff  = \ _ _ _ -> return ()
    {-# INLINE peekByteOff #-}
    {-# INLINE pokeByteOff #-}

{-# INLINE shapeSize #-}
shapeSize :: F.Foldable (Shape n)=>Shape n a -> Int
shapeSize  = \ as -> ( F.foldl (\ct _ -> ct +1) 0 as )

unShapeVector ::(UnBoxedShapeMorphism n a, T.Traversable (Shape n), UV.Unbox a) => UV.Vector  (Shape n a) -> (Int, Shape n (UV.Vector  a))
unShapeVector vs = runST  $
            do  (l,mvs) <- fmap unShapeMVector $  UV.unsafeThaw vs
                shpvs <- T.traverse UV.unsafeFreeze mvs
                return (l,shpvs)


reShapeVector::(UnBoxedShapeMorphism n a, T.Traversable (Shape n), UV.Unbox a)=>
      (Int, Shape n (UV.Vector   a)) -> UV.Vector (Shape n a)
reShapeVector (l,vs) = runST $
          do  mShapeV <-  T.traverse UV.unsafeThaw  vs
              mvShp <- return $ reShapeMVector (l,mShapeV)
              UV.unsafeFreeze mvShp


{- THis is a convenience type class so i dont have to export the constructors -}
class (UV.Unbox (Shape n a)) => UnBoxedShapeMorphism n a  where
   --unShapeVector :: UV.Vector (Shape n a) -> (Int, Shape n (UV.Vector a))
   --reShapeVector :: (Int, Shape n (UV.Vector a)) -> UV.Vector (Shape n a)

   unShapeMVector :: UVM.MVector s (Shape n a) -> (Int, Shape n (UV.MVector s a))
   reShapeMVector :: (Int, Shape n (UVM.MVector s  a)) -> UVM.MVector s (Shape n a)

instance (UV.Unbox a)=>  UnBoxedShapeMorphism 'Z a where
  --unShapeVector (V_ShapeZ l)= (l,Nil)
  unShapeMVector (MV_ShapeZ l) = (l,Nil )

  --reShapeVector (l,Nil)  = (V_ShapeZ l)
  reShapeMVector (l,Nil ) = (MV_ShapeZ l)


instance (UV.Unbox a)=>  UnBoxedShapeMorphism ('S 'Z) a  where
  --unShapeVector (V_ShapeSZ v)= (UV.length v, v :* Nil)

  unShapeMVector (MV_ShapeSZ v) = (UVM.length v,v:* Nil )

  --reShapeVector (l,v :* Nil)  = (V_ShapeSZ v)
  reShapeMVector (_,v :* _ ) = (MV_ShapeSZ v)

--UV.V_2
--UVM.MV_2
instance ((UV.Unbox a),UnBoxedShapeMorphism ('S n) a )=> UnBoxedShapeMorphism ('S ('S n)) a where
  --unShapeVector (V_ShapeSSN (UV.V_2 l vhead vtail))= (l, vhead :* snd (unShapeVector vtail)  )
  unShapeMVector (MV_ShapeSSN (UVM.MV_2 l vhead vtail)) = (l,vhead:*  snd (unShapeMVector vtail ))

  --reShapeVector (l,vh :* vt)  = (V_ShapeSSN (UV.V_2 l vh (reShapeVector (l,vt) )))
  reShapeMVector (l,vh :* vt ) = (MV_ShapeSSN (UVM.MV_2 l vh (reShapeMVector (l,vt) )))

newtype instance UV.MVector s (Shape 'Z a)  = MV_ShapeZ  Int
newtype instance UV.Vector    (Shape 'Z a) = V_ShapeZ  Int

newtype instance UV.MVector s (Shape ('S 'Z) a)  = MV_ShapeSZ (UV.MVector s a)
newtype instance UV.Vector    (Shape ('S 'Z) a) = V_ShapeSZ  (UV.Vector    a)

newtype instance UV.MVector s (Shape ('S ('S n)) a)  = MV_ShapeSSN (UV.MVector s (a, Shape ('S n) a) )
newtype instance UV.Vector    (Shape ('S ('S n)) a) = V_ShapeSSN  (UV.Vector   (a, Shape ('S n) a) )


instance UV.Unbox a => UV.Unbox (Shape 'Z a)
instance UV.Unbox a =>  UV.Unbox (Shape ('S 'Z) a)
instance (UV.Unbox a,UV.Unbox (Shape ('S n) a) )=> UV.Unbox (Shape ('S ('S n)) a)



instance UV.Unbox a => GMV.MVector UV.MVector  (Shape 'Z a) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}
  {-# INLINE basicInitialize #-}
  basicInitialize = \ (MV_ShapeZ _n) -> return ()
  basicLength  = \ (MV_ShapeZ n) ->  n
  basicUnsafeSlice  = \ _ m (MV_ShapeZ _) -> MV_ShapeZ m
  basicOverlaps = \ _ _  ->  False
  basicUnsafeNew  = \ n -> return (MV_ShapeZ n)
  basicUnsafeRead  = \ (MV_ShapeZ _) _ ->  return Nil
  basicUnsafeWrite  = \ (MV_ShapeZ _) _ Nil ->  return ()
  basicClear = \ _ -> return ()
  basicSet  =  \ (MV_ShapeZ _) Nil -> return ()
  basicUnsafeCopy  = \ (MV_ShapeZ _) (MV_ShapeZ _) ->  return ()
  basicUnsafeGrow  = \ (MV_ShapeZ n) m -> return $ MV_ShapeZ (n+m)

instance UV.Unbox a => GV.Vector UV.Vector  (Shape 'Z a) where
  {-# INLINE basicUnsafeFreeze #-}
  basicUnsafeFreeze  = \ (MV_ShapeZ n) ->  return $ V_ShapeZ n
  {-# INLINE basicUnsafeThaw #-}
  basicUnsafeThaw = \ (V_ShapeZ n)  -> return $ MV_ShapeZ n
  {-# INLINE basicLength #-}
  basicLength  = \(V_ShapeZ n) ->  n
  {-# INLINE basicUnsafeSlice #-}
  basicUnsafeSlice  = \ _ m (V_ShapeZ _) ->  V_ShapeZ m
  {-# INLINE basicUnsafeIndexM #-}
  basicUnsafeIndexM = \ (V_ShapeZ _) _  ->  return Nil
  {-# INLINE basicUnsafeCopy #-}
  basicUnsafeCopy  = \ (MV_ShapeZ _) (V_ShapeZ _) ->  return ()
  {-# INLINE elemseq #-}
  elemseq  =  \ _ -> seq

instance (UV.Unbox a) => GMV.MVector UV.MVector (Shape ('S 'Z) a) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}
  {-# INLINE basicInitialize #-}
  basicInitialize = \ (MV_ShapeSZ v) ->  GMV.basicInitialize v
  basicLength  = \(MV_ShapeSZ v)-> GMV.basicLength v
  basicUnsafeSlice  = \ i n (MV_ShapeSZ v) ->  MV_ShapeSZ $ GMV.basicUnsafeSlice i n v
  basicOverlaps = \ (MV_ShapeSZ v1) (MV_ShapeSZ v2)  ->  GMV.basicOverlaps v1 v2
  basicUnsafeNew  = \ n ->  MV_ShapeSZ `liftM` GMV.basicUnsafeNew n
  basicUnsafeReplicate  = \ n (a:*_) ->  MV_ShapeSZ `liftM` GMV.basicUnsafeReplicate n a
  basicUnsafeRead  = \ (MV_ShapeSZ v) i ->  ( :* Nil ) `liftM` GMV.basicUnsafeRead v i
  basicUnsafeWrite  = \ (MV_ShapeSZ v) i (a:* _) ->  GMV.basicUnsafeWrite v i a
  basicClear = \ (MV_ShapeSZ v)  ->  GMV.basicClear v
  basicSet =  \ (MV_ShapeSZ v) (a:*_)  ->  GMV.basicSet v a
  basicUnsafeCopy  = \ (MV_ShapeSZ v1) (MV_ShapeSZ v2) ->  GMV.basicUnsafeCopy v1 v2
  basicUnsafeMove  = \ (MV_ShapeSZ v1) (MV_ShapeSZ v2) -> GMV.basicUnsafeMove v1 v2
  basicUnsafeGrow  = \ (MV_ShapeSZ v) n ->  MV_ShapeSZ `liftM` GMV.basicUnsafeGrow v n

instance ( UV.Unbox a) => GV.Vector UV.Vector (Shape ('S 'Z) a ) where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeFreeze = \ (MV_ShapeSZ v)  ->  V_ShapeSZ `liftM` GV.basicUnsafeFreeze v
  basicUnsafeThaw = \ (V_ShapeSZ v)  ->  MV_ShapeSZ`liftM` GV.basicUnsafeThaw v
  basicLength  = \ (V_ShapeSZ v)-> GV.basicLength v
  basicUnsafeSlice  = \ i n (V_ShapeSZ v) ->  V_ShapeSZ $ GV.basicUnsafeSlice i n v
  basicUnsafeIndexM  = \ (V_ShapeSZ v) i -> ( :* Nil ) `liftM` GV.basicUnsafeIndexM v i
  basicUnsafeCopy   = \ (MV_ShapeSZ mv) (V_ShapeSZ v) -> GV.basicUnsafeCopy mv v
  elemseq  = \ _ (a:*_) z ->    GV.elemseq (undefined :: UV.Vector a) a z


instance (UV.Unbox a,UV.Unbox (Shape ('S n) a)) => GMV.MVector UV.MVector (Shape ('S ('S n)) a) where
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicOverlaps #-}
  {-# INLINE basicUnsafeNew #-}
  {-# INLINE basicUnsafeReplicate #-}
  {-# INLINE basicUnsafeRead #-}
  {-# INLINE basicUnsafeWrite #-}
  {-# INLINE basicClear #-}
  {-# INLINE basicSet #-}
  {-# INLINE basicUnsafeCopy #-}
  {-# INLINE basicUnsafeGrow #-}
  {-# INLINE basicInitialize #-}
  basicInitialize = \ (MV_ShapeSSN v) ->  GMV.basicInitialize v
  basicLength  = \ (MV_ShapeSSN v) -> GMV.basicLength v
  basicUnsafeSlice  = \ i n (MV_ShapeSSN v) -> MV_ShapeSSN $ GMV.basicUnsafeSlice i n v
  basicOverlaps  = \ (MV_ShapeSSN v1) (MV_ShapeSSN v2) -> GMV.basicOverlaps v1 v2
  basicUnsafeNew = \ n -> MV_ShapeSSN `liftM` GMV.basicUnsafeNew n
  basicUnsafeReplicate  = \ n (a :* as) ->  MV_ShapeSSN `liftM` GMV.basicUnsafeReplicate n (a,as)
  basicUnsafeRead = \ (MV_ShapeSSN v) i  ->  uncurry (:*) `liftM` GMV.basicUnsafeRead v i
  basicUnsafeWrite = \(MV_ShapeSSN v) i (a :* as )  -> GMV.basicUnsafeWrite v i (a,as)
  basicClear = \ (MV_ShapeSSN v)  ->  GMV.basicClear v
  basicSet  = \ (MV_ShapeSSN v) (a :* as) ->  GMV.basicSet v (a,as)
  basicUnsafeCopy  = \ (MV_ShapeSSN v1) (MV_ShapeSSN v2) -> GMV.basicUnsafeCopy v1 v2
  basicUnsafeMove  = \ (MV_ShapeSSN v1) (MV_ShapeSSN v2) ->  GMV.basicUnsafeMove v1 v2
  basicUnsafeGrow = \ (MV_ShapeSSN v) n  -> MV_ShapeSSN `liftM` GMV.basicUnsafeGrow v n


instance (UV.Unbox a,UV.Unbox (Shape ('S n) a)) =>  GV.Vector UV.Vector (Shape ('S ('S n)) a) where
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicUnsafeThaw #-}
  {-# INLINE basicLength #-}
  {-# INLINE basicUnsafeSlice #-}
  {-# INLINE basicUnsafeIndexM #-}
  {-# INLINE elemseq #-}
  basicUnsafeFreeze  = \ (MV_ShapeSSN v) ->  V_ShapeSSN `liftM` GV.basicUnsafeFreeze v
  basicUnsafeThaw = \ (V_ShapeSSN v)  ->  MV_ShapeSSN `liftM` GV.basicUnsafeThaw v
  basicLength = \ (V_ShapeSSN v)  -> GV.basicLength v
  basicUnsafeSlice = \ i n (V_ShapeSSN v)  -> V_ShapeSSN $ GV.basicUnsafeSlice i n v
  basicUnsafeIndexM  = \ (V_ShapeSSN v)  i -> uncurry (:*) `liftM` GV.basicUnsafeIndexM v i
  basicUnsafeCopy    =  \ (MV_ShapeSSN mv) (V_ShapeSSN v) -> GV.basicUnsafeCopy mv v
  elemseq = \  _ (a :* as) z ->  GV.elemseq (undefined :: UV.Vector a) a
                       $ GV.elemseq (undefined :: UV.Vector (Shape ('S n) a)) as z