#if __GLASGOW_HASKELL__ <= 708
#endif
module Data.Array.Accelerate.Array.Sugar (
  
  Array(..), Scalar, Vector, Segments,
  Arrays(..), ArraysR(..), ArraysFlavour(..), ArrRepr,
  
  Elt(..), EltRepr,
  
  liftToElt, liftToElt2, sinkFromElt, sinkFromElt2,
  
  DIM0, DIM1, DIM2, DIM3, DIM4, DIM5, DIM6, DIM7, DIM8, DIM9,
  
  Z(..), (:.)(..), All(..), Split(..), Any(..), Divide(..), Shape(..), Slice(..), Division(..),
  
  shape, (!), allocateArray, fromFunction, fromList, toList, concatVectors,
  
  TupleR, TupleRepr, tuple,
  Tuple(..), IsTuple, fromTuple, toTuple,
  Atuple(..), IsAtuple, fromAtuple, toAtuple,
  
  showShape, Foreign(..), sliceShape, enumSlices,
) where
import Control.DeepSeq
import Data.List                                                ( intercalate, transpose )
import Data.Typeable
import GHC.Exts                                                 ( IsList )
import Language.Haskell.TH                                      hiding ( Foreign )
import qualified GHC.Exts                                       as GHC
import Data.Array.Accelerate.Array.Data
import Data.Array.Accelerate.Error
import Data.Array.Accelerate.Product
import Data.Array.Accelerate.Type
import qualified Data.Array.Accelerate.Array.Representation     as Repr
data Z = Z
  deriving (Typeable, Show, Eq)
infixl 3 :.
data tail :. head = tail :. head
  deriving (Typeable, Eq)
instance (Show sh, Show sz) => Show (sh :. sz) where
  show (sh :. sz) = show sh ++ " :. " ++ show sz
data All = All
  deriving (Typeable, Show, Eq)
data Any sh = Any
  deriving (Typeable, Show, Eq)
data Split = Split
  deriving (Typeable, Show, Eq)
data Divide sh = Divide
  deriving (Typeable, Show, Eq)
type family EltRepr a :: *
type instance EltRepr ()              = ()
type instance EltRepr Z               = ()
type instance EltRepr (t:.h)          = (EltRepr t, EltRepr h)
type instance EltRepr All             = ()
type instance EltRepr (Any Z)         = ()
type instance EltRepr (Any (sh:.Int)) = (EltRepr (Any sh), ())
type instance EltRepr Int             = Int
type instance EltRepr Int8            = Int8
type instance EltRepr Int16           = Int16
type instance EltRepr Int32           = Int32
type instance EltRepr Int64           = Int64
type instance EltRepr Word            = Word
type instance EltRepr Word8           = Word8
type instance EltRepr Word16          = Word16
type instance EltRepr Word32          = Word32
type instance EltRepr Word64          = Word64
type instance EltRepr CShort          = CShort
type instance EltRepr CUShort         = CUShort
type instance EltRepr CInt            = CInt
type instance EltRepr CUInt           = CUInt
type instance EltRepr CLong           = CLong
type instance EltRepr CULong          = CULong
type instance EltRepr CLLong          = CLLong
type instance EltRepr CULLong         = CULLong
type instance EltRepr Float           = Float
type instance EltRepr Double          = Double
type instance EltRepr CFloat          = CFloat
type instance EltRepr CDouble         = CDouble
type instance EltRepr Bool            = Bool
type instance EltRepr Char            = Char
type instance EltRepr CChar           = CChar
type instance EltRepr CSChar          = CSChar
type instance EltRepr CUChar          = CUChar
type instance EltRepr (a, b)          = TupleRepr (EltRepr a, EltRepr b)
type instance EltRepr (a, b, c)       = TupleRepr (EltRepr a, EltRepr b, EltRepr c)
type instance EltRepr (a, b, c, d)    = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d)
type instance EltRepr (a, b, c, d, e) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e)
type instance EltRepr (a, b, c, d, e, f) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f)
type instance EltRepr (a, b, c, d, e, f, g) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f, EltRepr g)
type instance EltRepr (a, b, c, d, e, f, g, h) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f, EltRepr g, EltRepr h)
type instance EltRepr (a, b, c, d, e, f, g, h, i) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f, EltRepr g, EltRepr h, EltRepr i)
type instance EltRepr (a, b, c, d, e, f, g, h, i, j) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f, EltRepr g, EltRepr h, EltRepr i, EltRepr j)
type instance EltRepr (a, b, c, d, e, f, g, h, i, j, k) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f, EltRepr g, EltRepr h, EltRepr i, EltRepr j, EltRepr k)
type instance EltRepr (a, b, c, d, e, f, g, h, i, j, k, l) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f, EltRepr g, EltRepr h, EltRepr i, EltRepr j, EltRepr k, EltRepr l)
type instance EltRepr (a, b, c, d, e, f, g, h, i, j, k, l, m) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f, EltRepr g, EltRepr h, EltRepr i, EltRepr j, EltRepr k, EltRepr l, EltRepr m)
type instance EltRepr (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f, EltRepr g, EltRepr h, EltRepr i, EltRepr j, EltRepr k, EltRepr l, EltRepr m, EltRepr n)
type instance EltRepr (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) = TupleRepr (EltRepr a, EltRepr b, EltRepr c, EltRepr d, EltRepr e, EltRepr f, EltRepr g, EltRepr h, EltRepr i, EltRepr j, EltRepr k, EltRepr l, EltRepr m, EltRepr n, EltRepr o)
type IsTuple = IsProduct Elt
fromTuple :: IsTuple tup => tup -> TupleRepr tup
fromTuple = fromProd (Proxy :: Proxy Elt)
toTuple :: IsTuple tup => TupleRepr tup -> tup
toTuple = toProd (Proxy :: Proxy Elt)
class (Show a, Typeable a, Typeable (EltRepr a), ArrayElt (EltRepr a))
      => Elt a where
  eltType  ::  a -> TupleType (EltRepr a)
  fromElt  :: a -> EltRepr a
  toElt    :: EltRepr a -> a
instance Elt () where
  eltType _ = UnitTuple
  fromElt   = id
  toElt     = id
instance Elt Z where
  eltType _  = UnitTuple
  fromElt Z  = ()
  toElt ()   = Z
instance (Elt t, Elt h) => Elt (t:.h) where
  eltType (_::(t:.h))   = PairTuple (eltType (undefined :: t)) (eltType (undefined :: h))
  fromElt (t:.h)        = (fromElt t, fromElt h)
  toElt (t, h)          = toElt t :. toElt h
instance Elt All where
  eltType _     = UnitTuple
  fromElt All   = ()
  toElt ()      = All
instance Elt (Any Z) where
  eltType _     = UnitTuple
  fromElt _     = ()
  toElt _       = Any
instance Shape sh => Elt (Any (sh:.Int)) where
  eltType _     = PairTuple (eltType (undefined::Any sh)) UnitTuple
  fromElt _     = (fromElt (undefined :: Any sh), ())
  toElt _       = Any
instance Elt Int where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Int8 where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Int16 where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Int32 where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Int64 where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Word where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Word8 where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Word16 where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Word32 where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Word64 where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CShort where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CUShort where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CInt where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CUInt where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CLong where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CULong where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CLLong where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CULLong where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Float where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Double where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CFloat where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CDouble where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Bool where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt Char where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CChar where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CSChar where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance Elt CUChar where
  eltType       = singletonScalarType
  fromElt       = id
  toElt         = id
instance (Elt a, Elt b) => Elt (a, b) where
  eltType _             = PairTuple (PairTuple UnitTuple (eltType (undefined::a))) (eltType (undefined::b))
  fromElt (a,b)         = (((), fromElt a), fromElt b)
  toElt (((),a),b)      = (toElt a, toElt b)
instance (Elt a, Elt b, Elt c) => Elt (a, b, c) where
  eltType _             = PairTuple (eltType (undefined :: (a, b))) (eltType (undefined :: c))
  fromElt (a, b, c)     = (fromElt (a, b), fromElt c)
  toElt (ab, c)         = let (a, b) = toElt ab in (a, b, toElt c)
instance (Elt a, Elt b, Elt c, Elt d) => Elt (a, b, c, d) where
  eltType _             = PairTuple (eltType (undefined :: (a, b, c))) (eltType (undefined :: d))
  fromElt (a, b, c, d)  = (fromElt (a, b, c), fromElt d)
  toElt (abc, d)        = let (a, b, c) = toElt abc in (a, b, c, toElt d)
instance (Elt a, Elt b, Elt c, Elt d, Elt e) => Elt (a, b, c, d, e) where
  eltType _               = PairTuple (eltType (undefined :: (a, b, c, d))) (eltType (undefined :: e))
  fromElt (a, b, c, d, e) = (fromElt (a, b, c, d), fromElt e)
  toElt (abcd, e)         = let (a, b, c, d) = toElt abcd in (a, b, c, d, toElt e)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f) => Elt (a, b, c, d, e, f) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e)))
                (eltType (undefined :: f))
  fromElt (a, b, c, d, e, f) = (fromElt (a, b, c, d, e), fromElt f)
  toElt (abcde, f) = let (a, b, c, d, e) = toElt abcde in (a, b, c, d, e, toElt f)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g)
  => Elt (a, b, c, d, e, f, g) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e, f)))
                (eltType (undefined :: g))
  fromElt (a, b, c, d, e, f, g) = (fromElt (a, b, c, d, e, f), fromElt g)
  toElt (abcdef, g) = let (a, b, c, d, e, f) = toElt abcdef
                      in  (a, b, c, d, e, f, toElt g)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h)
  => Elt (a, b, c, d, e, f, g, h) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e, f, g)))
                (eltType (undefined :: h))
  fromElt (a, b, c, d, e, f, g, h) = (fromElt (a, b, c, d, e, f, g), fromElt h)
  toElt (abcdefg, h) = let (a, b, c, d, e, f, g) = toElt abcdefg
                       in  (a, b, c, d, e, f, g, toElt h)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i)
  => Elt (a, b, c, d, e, f, g, h, i) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e, f, g, h)))
                (eltType (undefined :: i))
  fromElt (a, b, c, d, e, f, g, h, i) = (fromElt (a, b, c, d, e, f, g, h), fromElt i)
  toElt (abcdefgh, i) = let (a, b, c, d, e, f, g, h) = toElt abcdefgh
                        in  (a, b, c, d, e, f, g, h, toElt i)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j)
  => Elt (a, b, c, d, e, f, g, h, i, j) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e, f, g, h, i)))
                (eltType (undefined :: j))
  fromElt (a, b, c, d, e, f, g, h, i, j) = (fromElt (a, b, c, d, e, f, g, h, i), fromElt j)
  toElt (abcdefghi, j) = let (a, b, c, d, e, f, g, h, i) = toElt abcdefghi
                         in  (a, b, c, d, e, f, g, h, i, toElt j)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j, Elt k)
  => Elt (a, b, c, d, e, f, g, h, i, j, k) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e, f, g, h, i, j)))
                (eltType (undefined :: k))
  fromElt (a, b, c, d, e, f, g, h, i, j, k) = (fromElt (a, b, c, d, e, f, g, h, i, j), fromElt k)
  toElt (abcdefghij, k) = let (a, b, c, d, e, f, g, h, i, j) = toElt abcdefghij
                          in  (a, b, c, d, e, f, g, h, i, j, toElt k)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j, Elt k, Elt l)
  => Elt (a, b, c, d, e, f, g, h, i, j, k, l) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e, f, g, h, i, j, k)))
                (eltType (undefined :: l))
  fromElt (a, b, c, d, e, f, g, h, i, j, k, l) = (fromElt (a, b, c, d, e, f, g, h, i, j, k), fromElt l)
  toElt (abcdefghijk, l) = let (a, b, c, d, e, f, g, h, i, j, k) = toElt abcdefghijk
                           in  (a, b, c, d, e, f, g, h, i, j, k, toElt l)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j, Elt k, Elt l, Elt m)
  => Elt (a, b, c, d, e, f, g, h, i, j, k, l, m) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e, f, g, h, i, j, k, l)))
                (eltType (undefined :: m))
  fromElt (a, b, c, d, e, f, g, h, i, j, k, l, m) = (fromElt (a, b, c, d, e, f, g, h, i, j, k, l), fromElt m)
  toElt (abcdefghijkl, m) = let (a, b, c, d, e, f, g, h, i, j, k, l) = toElt abcdefghijkl
                            in  (a, b, c, d, e, f, g, h, i, j, k, l, toElt m)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j, Elt k, Elt l, Elt m, Elt n)
  => Elt (a, b, c, d, e, f, g, h, i, j, k, l, m, n) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e, f, g, h, i, j, k, l, m)))
                (eltType (undefined :: n))
  fromElt (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = (fromElt (a, b, c, d, e, f, g, h, i, j, k, l, m), fromElt n)
  toElt (abcdefghijklm, n) = let (a, b, c, d, e, f, g, h, i, j, k, l, m) = toElt abcdefghijklm
                             in  (a, b, c, d, e, f, g, h, i, j, k, l, m, toElt n)
instance (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j, Elt k, Elt l, Elt m, Elt n, Elt o)
  => Elt (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) where
  eltType _
    = PairTuple (eltType (undefined :: (a, b, c, d, e, f, g, h, i, j, k, l, m, n)))
                (eltType (undefined :: o))
  fromElt (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) = (fromElt (a, b, c, d, e, f, g, h, i, j, k, l, m, n), fromElt o)
  toElt (abcdefghijklmn, o) = let (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = toElt abcdefghijklmn
                              in  (a, b, c, d, e, f, g, h, i, j, k, l, m, n, toElt o)
singletonScalarType :: IsScalar a => a -> TupleType a
singletonScalarType _ = SingleTuple scalarType
liftToElt :: (Elt a, Elt b)
          => (EltRepr a -> EltRepr b)
          -> (a -> b)
liftToElt f = toElt . f . fromElt
liftToElt2 :: (Elt a, Elt b, Elt c)
           => (EltRepr a -> EltRepr b -> EltRepr c)
           -> (a -> b -> c)
liftToElt2 f x y = toElt $ f (fromElt x) (fromElt y)
sinkFromElt :: (Elt a, Elt b)
            => (a -> b)
            -> (EltRepr a -> EltRepr b)
sinkFromElt f = fromElt . f . toElt
sinkFromElt2 :: (Elt a, Elt b, Elt c)
             => (a -> b -> c)
             -> (EltRepr a -> EltRepr b -> EltRepr c)
sinkFromElt2 f x y = fromElt $ f (toElt x) (toElt y)
class Typeable asm => Foreign asm where
  
  
  strForeign :: asm args -> String
  strForeign _ = "<foreign>"
  
  
  liftForeign :: asm args -> Q (TExp (asm args))
  liftForeign _ = $internalError "liftForeign" "not supported by this backend"
type family ArrRepr a :: *
type instance ArrRepr ()           = ()
type instance ArrRepr (Array sh e) = Array sh e
type instance ArrRepr (a, b)       = TupleRepr (ArrRepr a, ArrRepr b)
type instance ArrRepr (a, b, c)    = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c)
type instance ArrRepr (a, b, c, d) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d)
type instance ArrRepr (a, b, c, d, e) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e)
type instance ArrRepr (a, b, c, d, e, f) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f)
type instance ArrRepr (a, b, c, d, e, f, g) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f, ArrRepr g)
type instance ArrRepr (a, b, c, d, e, f, g, h) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f, ArrRepr g, ArrRepr h)
type instance ArrRepr (a, b, c, d, e, f, g, h, i) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f, ArrRepr g, ArrRepr h, ArrRepr i)
type instance ArrRepr (a, b, c, d, e, f, g, h, i, j) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f, ArrRepr g, ArrRepr h, ArrRepr i, ArrRepr j)
type instance ArrRepr (a, b, c, d, e, f, g, h, i, j, k) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f, ArrRepr g, ArrRepr h, ArrRepr i, ArrRepr j, ArrRepr k)
type instance ArrRepr (a, b, c, d, e, f, g, h, i, j, k, l) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f, ArrRepr g, ArrRepr h, ArrRepr i, ArrRepr j, ArrRepr k, ArrRepr l)
type instance ArrRepr (a, b, c, d, e, f, g, h, i, j, k, l, m) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f, ArrRepr g, ArrRepr h, ArrRepr i, ArrRepr j, ArrRepr k, ArrRepr l, ArrRepr m)
type instance ArrRepr (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f, ArrRepr g, ArrRepr h, ArrRepr i, ArrRepr j, ArrRepr k, ArrRepr l, ArrRepr m, ArrRepr n)
type instance ArrRepr (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) = TupleRepr (ArrRepr a, ArrRepr b, ArrRepr c, ArrRepr d, ArrRepr e, ArrRepr f, ArrRepr g, ArrRepr h, ArrRepr i, ArrRepr j, ArrRepr k, ArrRepr l, ArrRepr m, ArrRepr n, ArrRepr o)
type IsAtuple = IsProduct Arrays
fromAtuple :: IsAtuple tup => tup -> TupleRepr tup
fromAtuple = fromProd (Proxy :: Proxy Arrays)
toAtuple :: IsAtuple tup => TupleRepr tup -> tup
toAtuple = toProd (Proxy :: Proxy Arrays)
data ArraysR arrs where
  ArraysRunit  ::                                   ArraysR ()
  ArraysRarray :: (Shape sh, Elt e) =>              ArraysR (Array sh e)
  ArraysRpair  :: ArraysR arrs1 -> ArraysR arrs2 -> ArraysR (arrs1, arrs2)
data ArraysFlavour arrs where
  ArraysFunit  ::                                          ArraysFlavour ()
  ArraysFarray :: (Shape sh, Elt e)                     => ArraysFlavour (Array sh e)
  ArraysFtuple :: (IsAtuple arrs, ArrRepr arrs ~ (l,r)) => ArraysFlavour arrs
class (Typeable a, Typeable (ArrRepr a)) => Arrays a where
  arrays   :: a  -> ArraysR (ArrRepr a)
  flavour  :: a  -> ArraysFlavour a
  
  toArr    :: ArrRepr  a -> a
  fromArr  :: a -> ArrRepr  a
instance Arrays () where
  arrays  _ = ArraysRunit
  flavour _ = ArraysFunit
  
  toArr     = id
  fromArr   = id
instance (Shape sh, Elt e) => Arrays (Array sh e) where
  arrays _      = ArraysRarray
  flavour _     = ArraysFarray
  
  toArr         = id
  fromArr       = id
instance (Arrays a, Arrays b) => Arrays (a, b) where
  arrays  _             = ArraysRpair (ArraysRpair ArraysRunit (arrays (undefined::a))) (arrays (undefined::b))
  flavour _             = ArraysFtuple
  
  toArr    (((),a), b)  = (toArr a, toArr b)
  fromArr  (a, b)       = (((), fromArr a), fromArr b)
instance (Arrays a, Arrays b, Arrays c) => Arrays (a, b, c) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b))) (arrays (undefined::c))
  flavour _             = ArraysFtuple
  
  toArr    (ab, c)      = let (a, b) = toArr ab in (a, b, toArr c)
  fromArr  (a, b, c)    = (fromArr (a, b), fromArr c)
instance (Arrays a, Arrays b, Arrays c, Arrays d) => Arrays (a, b, c, d) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c))) (arrays (undefined::d))
  flavour _             = ArraysFtuple
  
  toArr    (abc, d)     = let (a, b, c) = toArr abc in (a, b, c, toArr d)
  fromArr  (a, b, c, d) = (fromArr (a, b, c), fromArr d)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e) => Arrays (a, b, c, d, e) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d))) (arrays (undefined::e))
  flavour _             = ArraysFtuple
  
  toArr    (abcd, e)    = let (a, b, c, d) = toArr abcd in (a, b, c, d, toArr e)
  fromArr  (a, b, c, d, e) = (fromArr (a, b, c, d), fromArr e)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f)
  => Arrays (a, b, c, d, e, f) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e))) (arrays (undefined::f))
  flavour _             = ArraysFtuple
  
  toArr    (abcde, f)   = let (a, b, c, d, e) = toArr abcde in (a, b, c, d, e, toArr f)
  fromArr  (a, b, c, d, e, f) = (fromArr (a, b, c, d, e), fromArr f)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g)
  => Arrays (a, b, c, d, e, f, g) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e, f))) (arrays (undefined::g))
  flavour _             = ArraysFtuple
  
  toArr    (abcdef, g)   = let (a, b, c, d, e, f) = toArr abcdef in (a, b, c, d, e, f, toArr g)
  fromArr  (a, b, c, d, e, f, g) = (fromArr (a, b, c, d, e, f), fromArr g)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h)
  => Arrays (a, b, c, d, e, f, g, h) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e, f, g))) (arrays (undefined::h))
  flavour _             = ArraysFtuple
  
  toArr    (abcdefg, h)   = let (a, b, c, d, e, f, g) = toArr abcdefg in (a, b, c, d, e, f, g, toArr h)
  fromArr  (a, b, c, d, e, f, g, h) = (fromArr (a, b, c, d, e, f, g), fromArr h)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i)
  => Arrays (a, b, c, d, e, f, g, h, i) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e, f, g, h))) (arrays (undefined::i))
  flavour _             = ArraysFtuple
  
  toArr    (abcdefgh, i) = let (a, b, c, d, e, f, g, h) = toArr abcdefgh in (a, b, c, d, e, f, g, h, toArr i)
  fromArr  (a, b, c, d, e, f, g, h, i) = (fromArr (a, b, c, d, e, f, g, h), fromArr i)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j)
  => Arrays (a, b, c, d, e, f, g, h, i, j) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e, f, g, h, i))) (arrays (undefined::j))
  flavour _             = ArraysFtuple
  
  toArr    (abcdefghi, j) = let (a, b, c, d, e, f, g, h, i) = toArr abcdefghi in (a, b, c, d, e, f, g, h, i, toArr j)
  fromArr  (a, b, c, d, e, f, g, h, i, j) = (fromArr (a, b, c, d, e, f, g, h, i), fromArr j)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j, Arrays k)
  => Arrays (a, b, c, d, e, f, g, h, i, j, k) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e, f, g, h, i, j))) (arrays (undefined::k))
  flavour _             = ArraysFtuple
  
  toArr    (abcdefghij, k) = let (a, b, c, d, e, f, g, h, i, j) = toArr abcdefghij in (a, b, c, d, e, f, g, h, i, j, toArr k)
  fromArr  (a, b, c, d, e, f, g, h, i, j, k) = (fromArr (a, b, c, d, e, f, g, h, i, j), fromArr k)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j, Arrays k, Arrays l)
  => Arrays (a, b, c, d, e, f, g, h, i, j, k, l) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e, f, g, h, i, j, k))) (arrays (undefined::l))
  flavour _             = ArraysFtuple
  
  toArr    (abcdefghijk, l) = let (a, b, c, d, e, f, g, h, i, j, k) = toArr abcdefghijk in (a, b, c, d, e, f, g, h, i, j, k, toArr l)
  fromArr  (a, b, c, d, e, f, g, h, i, j, k, l) = (fromArr (a, b, c, d, e, f, g, h, i, j, k), fromArr l)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j, Arrays k, Arrays l, Arrays m)
  => Arrays (a, b, c, d, e, f, g, h, i, j, k, l, m) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e, f, g, h, i, j, k, l))) (arrays (undefined::m))
  flavour _             = ArraysFtuple
  
  toArr    (abcdefghijkl, m) = let (a, b, c, d, e, f, g, h, i, j, k, l) = toArr abcdefghijkl in (a, b, c, d, e, f, g, h, i, j, k, l, toArr m)
  fromArr  (a, b, c, d, e, f, g, h, i, j, k, l, m) = (fromArr (a, b, c, d, e, f, g, h, i, j, k, l), fromArr m)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j, Arrays k, Arrays l, Arrays m, Arrays n)
  => Arrays (a, b, c, d, e, f, g, h, i, j, k, l, m, n) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e, f, g, h, i, j, k, l, m))) (arrays (undefined::n))
  flavour _             = ArraysFtuple
  
  toArr    (abcdefghijklm, n) = let (a, b, c, d, e, f, g, h, i, j, k, l, m) = toArr abcdefghijklm in (a, b, c, d, e, f, g, h, i, j, k, l, m, toArr n)
  fromArr  (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = (fromArr (a, b, c, d, e, f, g, h, i, j, k, l, m), fromArr n)
instance (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j, Arrays k, Arrays l, Arrays m, Arrays n, Arrays o)
  => Arrays (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) where
  arrays  _             = ArraysRpair (arrays (undefined :: (a, b, c, d, e, f, g, h, i, j, k, l, m, n))) (arrays (undefined::o))
  flavour _             = ArraysFtuple
  
  toArr    (abcdefghijklmn, o) = let (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = toArr abcdefghijklmn in (a, b, c, d, e, f, g, h, i, j, k, l, m, n, toArr o)
  fromArr  (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) = (fromArr (a, b, c, d, e, f, g, h, i, j, k, l, m, n), fromArr o)
type TupleRepr a = ProdRepr a
data Tuple c t where
  NilTup  ::                              Tuple c ()
  SnocTup :: Elt t => Tuple c s -> c t -> Tuple c (s, t)
data Atuple c t where
  NilAtup  ::                                  Atuple c ()
  SnocAtup :: Arrays a => Atuple c s -> c a -> Atuple c (s, a)
type TupleR a = ProdR Elt a
tuple :: IsTuple tup =>  tup -> TupleR (TupleRepr tup)
tuple = prod (Proxy :: Proxy Elt)
data Array sh e where
  Array :: (Shape sh, Elt e)
        => EltRepr sh                 
        -> ArrayData (EltRepr e)      
        -> Array sh e
deriving instance Typeable Array
instance (Eq sh, Eq e) => Eq (Array sh e) where
  arr1@Array{} == arr2@Array{} = shape arr1 == shape arr2 && toList arr1 == toList arr2
  arr1@Array{} /= arr2@Array{} = shape arr1 /= shape arr2 || toList arr1 /= toList arr2
#if __GLASGOW_HASKELL__ >= 710
instance Show (Scalar e) where
  show arr@Array{} =
    "Scalar Z " ++ show (toList arr)
instance Show (Vector e) where
  show arr@Array{} =
    "Vector (" ++ showShape (shape arr) ++ ") " ++ show (toList arr)
instance Show (Array DIM2 e) where
  show arr@Array{} =
    "Matrix (" ++ showShape (shape arr) ++ ") " ++ showMat (toMatrix (toList arr))
    where
      Z :. _ :. cols    = shape arr
      toMatrix []       = []
      toMatrix xs       = let (r,rs) = splitAt cols xs
                          in  r : toMatrix rs
      
      showMat []        = "[]"
      showMat mat       = "\n  " ++ ppMat (map (map show) mat)
      
      ppRow row         = concatMap (++",") row
      ppMat mat         = "[" ++ init (intercalate "\n   " (map ppRow (ppColumns mat))) ++ "]"
      ppColumns         = transpose . map (\col -> pad (width col) col) . transpose
        where
          extra = 0
          width = maximum . map length
          pad w = map (\x -> replicate (w  length x + extra) ' ' ++ x)
#endif
instance  Show (Array sh e) where
  show arr@Array{} =
    "Array (" ++ showShape (shape arr) ++ ") " ++ show (toList arr)
instance Elt e => IsList (Vector e) where
  type Item (Vector e) = e
  toList         = toList
  fromListN n xs = fromList (Z:.n) xs
  fromList xs    = GHC.fromListN (length xs) xs
instance NFData (Array sh e) where
  rnf (Array sh ad) = Repr.size sh `seq` go arrayElt ad `seq` ()
    where
      go :: ArrayEltR e' -> ArrayData e' -> ()
      go ArrayEltRunit         AD_Unit         = ()
      go ArrayEltRint          (AD_Int ua)     = rnf ua
      go ArrayEltRint8         (AD_Int8 ua)    = rnf ua
      go ArrayEltRint16        (AD_Int16 ua)   = rnf ua
      go ArrayEltRint32        (AD_Int32 ua)   = rnf ua
      go ArrayEltRint64        (AD_Int64 ua)   = rnf ua
      go ArrayEltRword         (AD_Word ua)    = rnf ua
      go ArrayEltRword8        (AD_Word8 ua)   = rnf ua
      go ArrayEltRword16       (AD_Word16 ua)  = rnf ua
      go ArrayEltRword32       (AD_Word32 ua)  = rnf ua
      go ArrayEltRword64       (AD_Word64 ua)  = rnf ua
      go ArrayEltRcshort       (AD_CShort ua)  = rnf ua
      go ArrayEltRcushort      (AD_CUShort ua) = rnf ua
      go ArrayEltRcint         (AD_CInt ua)    = rnf ua
      go ArrayEltRcuint        (AD_CUInt ua)   = rnf ua
      go ArrayEltRclong        (AD_CLong ua)   = rnf ua
      go ArrayEltRculong       (AD_CULong ua)  = rnf ua
      go ArrayEltRcllong       (AD_CLLong ua)  = rnf ua
      go ArrayEltRcullong      (AD_CULLong ua) = rnf ua
      go ArrayEltRfloat        (AD_Float ua)   = rnf ua
      go ArrayEltRdouble       (AD_Double ua)  = rnf ua
      go ArrayEltRcfloat       (AD_CFloat ua)  = rnf ua
      go ArrayEltRcdouble      (AD_CDouble ua) = rnf ua
      go ArrayEltRbool         (AD_Bool ua)    = rnf ua
      go ArrayEltRchar         (AD_Char ua)    = rnf ua
      go ArrayEltRcchar        (AD_CChar ua)   = rnf ua
      go ArrayEltRcschar       (AD_CSChar ua)  = rnf ua
      go ArrayEltRcuchar       (AD_CUChar ua)  = rnf ua
      go (ArrayEltRpair r1 r2) (AD_Pair a1 a2) = go r1 a1 `seq` go r2 a2 `seq` ()
type Scalar e = Array DIM0 e
type Vector e = Array DIM1 e
type Segments i = Vector i
type DIM0 = Z
type DIM1 = DIM0:.Int
type DIM2 = DIM1:.Int
type DIM3 = DIM2:.Int
type DIM4 = DIM3:.Int
type DIM5 = DIM4:.Int
type DIM6 = DIM5:.Int
type DIM7 = DIM6:.Int
type DIM8 = DIM7:.Int
type DIM9 = DIM8:.Int
class (Elt sh, Elt (Any sh), Repr.Shape (EltRepr sh), FullShape sh ~ sh, CoSliceShape sh ~ sh, SliceShape sh ~ Z)
       => Shape sh where
  
  rank   :: sh -> Int
  
  size   :: sh -> Int
  
  empty :: sh
  
  ignore :: sh
  
  intersect :: sh -> sh -> sh
  
  union :: sh -> sh -> sh
  
  
  
  toIndex   :: sh -> sh -> Int
  
  fromIndex :: sh -> Int -> sh
  
  
  
  iter  :: sh -> (sh -> a) -> (a -> a -> a) -> a -> a
  
  iter1 :: sh -> (sh -> a) -> (a -> a -> a) -> a
  
  rangeToShape ::  (sh, sh) -> sh
  
  shapeToRange ::  sh -> (sh, sh)
  
  shapeToList :: sh -> [Int]
  
  listToShape :: [Int] -> sh
  
  sliceAnyIndex :: sh -> Repr.SliceIndex (EltRepr (Any sh)) (EltRepr sh) () (EltRepr sh)
  
  sliceNoneIndex :: sh -> Repr.SliceIndex (EltRepr sh) () (EltRepr sh) (EltRepr sh)
  rank                  = Repr.rank . fromElt
  size                  = Repr.size . fromElt
  empty                 = toElt Repr.empty
  
  
  ignore                = toElt Repr.ignore
  intersect sh1 sh2     = toElt (Repr.intersect (fromElt sh1) (fromElt sh2))
  union sh1 sh2         = toElt (Repr.union (fromElt sh1) (fromElt sh2))
  fromIndex sh ix       = toElt (Repr.fromIndex (fromElt sh) ix)
  toIndex sh ix         = Repr.toIndex (fromElt sh) (fromElt ix)
  iter sh f c r         = Repr.iter  (fromElt sh) (f . toElt) c r
  iter1 sh f r          = Repr.iter1 (fromElt sh) (f . toElt) r
  rangeToShape (low, high)
    = toElt (Repr.rangeToShape (fromElt low, fromElt high))
  shapeToRange ix
    = let (low, high) = Repr.shapeToRange (fromElt ix)
      in
      (toElt low, toElt high)
  shapeToList = Repr.shapeToList . fromElt
  listToShape = toElt . Repr.listToShape
instance Shape Z where
  sliceAnyIndex  _ = Repr.SliceNil
  sliceNoneIndex _ = Repr.SliceNil
instance Shape sh => Shape (sh:.Int) where
  sliceAnyIndex  _ = Repr.SliceAll   (sliceAnyIndex  (undefined :: sh))
  sliceNoneIndex _ = Repr.SliceFixed (sliceNoneIndex (undefined :: sh))
class (Elt sl, Shape (SliceShape sl), Shape (CoSliceShape sl), Shape (FullShape sl))
       => Slice sl where
  type SliceShape   sl :: *     
  type CoSliceShape sl :: *     
  type FullShape    sl :: *     
  sliceIndex :: sl  -> Repr.SliceIndex (EltRepr sl)
                                    (EltRepr (SliceShape   sl))
                                    (EltRepr (CoSliceShape sl))
                                    (EltRepr (FullShape    sl))
instance Slice Z where
  type SliceShape   Z = Z
  type CoSliceShape Z = Z
  type FullShape    Z = Z
  sliceIndex _ = Repr.SliceNil
instance Slice sl => Slice (sl:.All) where
  type SliceShape   (sl:.All) = SliceShape   sl :. Int
  type CoSliceShape (sl:.All) = CoSliceShape sl
  type FullShape    (sl:.All) = FullShape    sl :. Int
  sliceIndex _ = Repr.SliceAll (sliceIndex (undefined :: sl))
instance Slice sl => Slice (sl:.Int) where
  type SliceShape   (sl:.Int) = SliceShape   sl
  type CoSliceShape (sl:.Int) = CoSliceShape sl :. Int
  type FullShape    (sl:.Int) = FullShape    sl :. Int
  sliceIndex _ = Repr.SliceFixed (sliceIndex (undefined :: sl))
instance Shape sh => Slice (Any sh) where
  type SliceShape   (Any sh) = sh
  type CoSliceShape (Any sh) = Z
  type FullShape    (Any sh) = sh
  sliceIndex _ = sliceAnyIndex (undefined :: sh)
class (Slice (DivisionSlice sl))
       => Division sl where
  type DivisionSlice sl :: *     
  slicesIndex :: slix ~ DivisionSlice sl
              => sl 
              -> Repr.SliceIndex (EltRepr slix)
                                 (EltRepr (SliceShape   slix))
                                 (EltRepr (CoSliceShape slix))
                                 (EltRepr (FullShape    slix))
instance Division Z where
  type DivisionSlice   Z = Z
  slicesIndex _ = Repr.SliceNil
instance Division sl => Division (sl:.All) where
  type DivisionSlice  (sl:.All) = DivisionSlice sl :. All
  slicesIndex _ = Repr.SliceAll (slicesIndex (undefined :: sl))
instance Division sl => Division (sl:.Split) where
  type DivisionSlice (sl:.Split) = DivisionSlice sl :. Int
  slicesIndex _ = Repr.SliceFixed (slicesIndex (undefined :: sl))
instance Shape sh => Division (Any sh) where
  type DivisionSlice (Any sh) = Any sh
  slicesIndex _ = sliceAnyIndex (undefined :: sh)
instance (Shape sh, Slice sh) => Division (Divide sh) where
  type DivisionSlice (Divide sh) = sh
  slicesIndex _ = sliceNoneIndex (undefined :: sh)
shape :: Shape sh => Array sh e -> sh
shape (Array sh _) = toElt sh
infixl 9 !
(!) :: Array sh e -> sh -> e
(!) (Array sh adata) ix = toElt (adata `unsafeIndexArrayData` toIndex (toElt sh) ix)
fromFunction :: (Shape sh, Elt e) => sh -> (sh -> e) -> Array sh e
fromFunction sh f = adata `seq` Array (fromElt sh) adata
  where
    (adata, _) = runArrayData $ do
                   arr <- newArrayData (size sh)
                   let write ix = unsafeWriteArrayData arr (toIndex sh ix)
                                                           (fromElt (f ix))
                   iter sh write (>>) (return ())
                   return (arr, undefined)
concatVectors :: Elt e => [Vector e] -> Vector e
concatVectors vs = adata `seq` Array ((), len) adata
  where
    offsets     = scanl (+) 0 (map (size . shape) vs)
    len         = last offsets
    (adata, _)  = runArrayData $ do
              arr <- newArrayData len
              sequence_ [ unsafeWriteArrayData arr (i + k) (unsafeIndexArrayData ad i)
                        | (Array ((), n) ad, k) <- vs `zip` offsets
                        , i <- [0 .. n  1] ]
              return (arr, undefined)
allocateArray :: (Shape sh, Elt e) => sh -> IO (Array sh e)
allocateArray sh = adata `seq` return (Array (fromElt sh) adata)
  where
    (adata, _) = runArrayData $ (,undefined) `fmap` newArrayData (size sh)
fromList :: (Shape sh, Elt e) => sh -> [e] -> Array sh e
fromList sh xs = adata `seq` Array (fromElt sh) adata
  where
    
    
    
    !n          = size sh
    (adata, _)  = runArrayData $ do
                    arr <- newArrayData n
                    let go !i _ | i >= n = return ()
                        go !i (v:vs)     = unsafeWriteArrayData arr i (fromElt v) >> go (i+1) vs
                        go _  []         = error "Data.Array.Accelerate.fromList: not enough input data"
                    
                    go 0 xs
                    return (arr, undefined)
toList :: forall sh e. Array sh e -> [e]
toList (Array sh adata) = go 0
  where
    
    
    
    !n                  = Repr.size sh
    go !i | i >= n      = []
          | otherwise   = toElt (adata `unsafeIndexArrayData` i) : go (i+1)
showShape :: Shape sh => sh -> String
showShape = foldr (\sh str -> str ++ " :. " ++ show sh) "Z" . shapeToList
sliceShape :: forall slix co sl dim. (Shape sl, Shape dim)
           => Repr.SliceIndex slix (EltRepr sl) co (EltRepr dim)
           -> dim
           -> sl
sliceShape slix = toElt . Repr.sliceShape slix . fromElt
enumSlices :: forall slix co sl dim. (Elt slix, Elt dim)
           => Repr.SliceIndex (EltRepr slix) sl co (EltRepr dim)
           -> dim    
           -> [slix] 
enumSlices slix = map toElt . Repr.enumSlices slix . fromElt