{-# LANGUAGE DeriveDataTypeable    #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE StandaloneDeriving    #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE TypeOperators         #-}
{-# OPTIONS_HADDOCK hide #-}
module Data.Array.Accelerate.Smart (
  
  Acc(..), PreAcc(..), Exp(..), PreExp(..), Boundary(..), PreBoundary(..), Stencil(..), Level,
  
  constant, undef,
  
  tup2, tup3, tup4, tup5, tup6, tup7, tup8, tup9, tup10, tup11, tup12, tup13, tup14, tup15, tup16,
  untup2, untup3, untup4, untup5, untup6, untup7, untup8, untup9, untup10, untup11, untup12, untup13, untup14, untup15, untup16,
  atup2, atup3, atup4, atup5, atup6, atup7, atup8, atup9, atup10, atup11, atup12, atup13, atup14, atup15, atup16,
  unatup2, unatup3, unatup4, unatup5, unatup6, unatup7, unatup8, unatup9, unatup10, unatup11, unatup12, unatup13, unatup14, unatup15, unatup16,
  
  mkMinBound, mkMaxBound, mkPi,
  mkSin, mkCos, mkTan,
  mkAsin, mkAcos, mkAtan,
  mkSinh, mkCosh, mkTanh,
  mkAsinh, mkAcosh, mkAtanh,
  mkExpFloating, mkSqrt, mkLog,
  mkFPow, mkLogBase,
  mkTruncate, mkRound, mkFloor, mkCeiling,
  mkAtan2,
  
  mkAdd, mkSub, mkMul, mkNeg, mkAbs, mkSig, mkQuot, mkRem, mkQuotRem, mkIDiv, mkMod, mkDivMod,
  mkBAnd, mkBOr, mkBXor, mkBNot, mkBShiftL, mkBShiftR, mkBRotateL, mkBRotateR, mkPopCount, mkCountLeadingZeros, mkCountTrailingZeros,
  mkFDiv, mkRecip, mkLt, mkGt, mkLtEq, mkGtEq, mkEq, mkNEq, mkMax, mkMin,
  mkLAnd, mkLOr, mkLNot, mkIsNaN, mkIsInfinite,
  
  mkOrd, mkChr, mkBoolToInt, mkFromIntegral, mkToFloating, mkBitcast, mkUnsafeCoerce,
  
  ($$), ($$$), ($$$$), ($$$$$),
  
  showPreAccOp, showPreExpOp,
) where
import Prelude                                  hiding ( exp )
import Data.List
import Data.Typeable
import Data.Array.Accelerate.Type
import Data.Array.Accelerate.Array.Sugar
import Data.Array.Accelerate.Product
import Data.Array.Accelerate.AST                hiding ( PreOpenAcc(..), OpenAcc(..), Acc
                                                       , PreOpenExp(..), OpenExp, PreExp, Exp
                                                       , Stencil(..), PreBoundary(..), Boundary
                                                       , showPreAccOp, showPreExpOp )
import qualified Data.Array.Accelerate.AST      as AST
newtype Acc a = Acc (PreAcc Acc Exp a)
deriving instance Typeable Acc
type Level = Int
data PreAcc acc exp as where
    
  Atag          :: Arrays as
                => Level                        
                -> PreAcc acc exp as
  Pipe          :: (Arrays as, Arrays bs, Arrays cs)
                => (Acc as -> acc bs)
                -> (Acc bs -> acc cs)
                -> acc as
                -> PreAcc acc exp cs
  Aforeign      :: (Arrays as, Arrays bs, Foreign asm)
                => asm (as -> bs)
                -> (Acc as -> Acc bs)
                -> acc as
                -> PreAcc acc exp bs
  Acond         :: Arrays as
                => exp Bool
                -> acc as
                -> acc as
                -> PreAcc acc exp as
  Awhile        :: Arrays arrs
                => (Acc arrs -> acc (Scalar Bool))
                -> (Acc arrs -> acc arrs)
                -> acc arrs
                -> PreAcc acc exp arrs
  Atuple        :: (Arrays arrs, IsAtuple arrs)
                => Atuple acc (TupleRepr arrs)
                -> PreAcc acc exp arrs
  Aprj          :: (Arrays arrs, IsAtuple arrs, Arrays a)
                => TupleIdx (TupleRepr arrs) a
                ->        acc     arrs
                -> PreAcc acc exp a
  Use           :: Arrays arrs
                => arrs
                -> PreAcc acc exp arrs
  Unit          :: Elt e
                => exp e
                -> PreAcc acc exp (Scalar e)
  Generate      :: (Shape sh, Elt e)
                => exp sh
                -> (Exp sh -> exp e)
                -> PreAcc acc exp (Array sh e)
  Reshape       :: (Shape sh, Shape sh', Elt e)
                => exp sh
                -> acc (Array sh' e)
                -> PreAcc acc exp (Array sh e)
  Replicate     :: (Slice slix, Elt e)
                => exp slix
                -> acc            (Array (SliceShape slix) e)
                -> PreAcc acc exp (Array (FullShape  slix) e)
  Slice         :: (Slice slix, Elt e)
                => acc            (Array (FullShape  slix) e)
                -> exp slix
                -> PreAcc acc exp (Array (SliceShape slix) e)
  Map           :: (Shape sh, Elt e, Elt e')
                => (Exp e -> exp e')
                -> acc (Array sh e)
                -> PreAcc acc exp (Array sh e')
  ZipWith       :: (Shape sh, Elt e1, Elt e2, Elt e3)
                => (Exp e1 -> Exp e2 -> exp e3)
                -> acc (Array sh e1)
                -> acc (Array sh e2)
                -> PreAcc acc exp (Array sh e3)
  Fold          :: (Shape sh, Elt e)
                => (Exp e -> Exp e -> exp e)
                -> exp e
                -> acc (Array (sh:.Int) e)
                -> PreAcc acc exp (Array sh e)
  Fold1         :: (Shape sh, Elt e)
                => (Exp e -> Exp e -> exp e)
                -> acc (Array (sh:.Int) e)
                -> PreAcc acc exp (Array sh e)
  FoldSeg       :: (Shape sh, Elt e, Elt i, IsIntegral i)
                => (Exp e -> Exp e -> exp e)
                -> exp e
                -> acc (Array (sh:.Int) e)
                -> acc (Segments i)
                -> PreAcc acc exp (Array (sh:.Int) e)
  Fold1Seg      :: (Shape sh, Elt e, Elt i, IsIntegral i)
                => (Exp e -> Exp e -> exp e)
                -> acc (Array (sh:.Int) e)
                -> acc (Segments i)
                -> PreAcc acc exp (Array (sh:.Int) e)
  Scanl         :: (Shape sh, Elt e)
                => (Exp e -> Exp e -> exp e)
                -> exp e
                -> acc (Array (sh :. Int) e)
                -> PreAcc acc exp (Array (sh :. Int) e)
  Scanl'        :: (Shape sh, Elt e)
                => (Exp e -> Exp e -> exp e)
                -> exp e
                -> acc (Array (sh :. Int) e)
                -> PreAcc acc exp (Array (sh :. Int) e, Array sh e)
  Scanl1        :: (Shape sh, Elt e)
                => (Exp e -> Exp e -> exp e)
                -> acc (Array (sh :. Int) e)
                -> PreAcc acc exp (Array (sh :. Int) e)
  Scanr         :: (Shape sh, Elt e)
                => (Exp e -> Exp e -> exp e)
                -> exp e
                -> acc (Array (sh :. Int) e)
                -> PreAcc acc exp (Array (sh :. Int) e)
  Scanr'        :: (Shape sh, Elt e)
                => (Exp e -> Exp e -> exp e)
                -> exp e
                -> acc (Array (sh :. Int) e)
                -> PreAcc acc exp (Array (sh :. Int) e, Array sh e)
  Scanr1        :: (Shape sh, Elt e)
                => (Exp e -> Exp e -> exp e)
                -> acc (Array (sh :. Int) e)
                -> PreAcc acc exp (Array (sh :. Int) e)
  Permute       :: (Shape sh, Shape sh', Elt e)
                => (Exp e -> Exp e -> exp e)
                -> acc (Array sh' e)
                -> (Exp sh -> exp sh')
                -> acc (Array sh e)
                -> PreAcc acc exp (Array sh' e)
  Backpermute   :: (Shape sh, Shape sh', Elt e)
                => exp sh'
                -> (Exp sh' -> exp sh)
                -> acc (Array sh e)
                -> PreAcc acc exp (Array sh' e)
  Stencil       :: (Shape sh, Elt a, Elt b, Stencil sh a stencil)
                => (stencil -> exp b)
                -> PreBoundary acc exp (Array sh a)
                -> acc (Array sh a)
                -> PreAcc acc exp (Array sh b)
  Stencil2      :: (Shape sh, Elt a, Elt b, Elt c, Stencil sh a stencil1, Stencil sh b stencil2)
                => (stencil1 -> stencil2 -> exp c)
                -> PreBoundary acc exp (Array sh a)
                -> acc (Array sh a)
                -> PreBoundary acc exp (Array sh b)
                -> acc (Array sh b)
                -> PreAcc acc exp (Array sh c)
  
  
  
newtype Exp t = Exp (PreExp Acc Exp t)
deriving instance Typeable Exp
data PreExp acc exp t where
    
  Tag           :: Elt t
                => Level                        
                -> PreExp acc exp t
  
  Const         :: Elt t
                => t
                -> PreExp acc exp t
  Tuple         :: (Elt t, IsTuple t)
                => Tuple exp (TupleRepr t)
                -> PreExp acc exp t
  Prj           :: (Elt t, IsTuple t, Elt e)
                => TupleIdx (TupleRepr t) e
                -> exp t
                -> PreExp acc exp e
  IndexNil      :: PreExp acc exp Z
  IndexCons     :: (Slice sl, Elt a)
                => exp sl
                -> exp a
                -> PreExp acc exp (sl:.a)
  IndexHead     :: (Slice sl, Elt a)
                => exp (sl:.a)
                -> PreExp acc exp a
  IndexTail     :: (Slice sl, Elt a)
                => exp (sl:.a)
                -> PreExp acc exp sl
  IndexAny      :: Shape sh
                => PreExp acc exp (Any sh)
  ToIndex       :: Shape sh
                => exp sh
                -> exp sh
                -> PreExp acc exp Int
  FromIndex     :: Shape sh
                => exp sh
                -> exp Int
                -> PreExp acc exp sh
  Cond          :: Elt t
                => exp Bool
                -> exp t
                -> exp t
                -> PreExp acc exp t
  While         :: Elt t
                => (Exp t -> exp Bool)
                -> (Exp t -> exp t)
                -> exp t
                -> PreExp acc exp t
  PrimConst     :: Elt t
                => PrimConst t
                -> PreExp acc exp t
  PrimApp       :: (Elt a, Elt r)
                => PrimFun (a -> r)
                -> exp a
                -> PreExp acc exp r
  Index         :: (Shape sh, Elt t)
                => acc (Array sh t)
                -> exp sh
                -> PreExp acc exp t
  LinearIndex   :: (Shape sh, Elt t)
                => acc (Array sh t)
                -> exp Int
                -> PreExp acc exp t
  Shape         :: (Shape sh, Elt e)
                => acc (Array sh e)
                -> PreExp acc exp sh
  ShapeSize     :: Shape sh
                => exp sh
                -> PreExp acc exp Int
  Intersect     :: Shape sh
                => exp sh
                -> exp sh
                -> PreExp acc exp sh
  Union         :: Shape sh
                => exp sh
                -> exp sh
                -> PreExp acc exp sh
  Foreign       :: (Elt x, Elt y, Foreign asm)
                => asm (x -> y)
                -> (Exp x -> Exp y) 
                -> exp x
                -> PreExp acc exp y
  Undef         :: Elt t
                => PreExp acc exp t
  Coerce        :: (Elt a, Elt b)
                => exp a
                -> PreExp acc exp b
atup2 :: (Arrays a, Arrays b)
      => (Acc a, Acc b)
      -> Acc (a, b)
atup2 (a, b)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
atup3 :: (Arrays a, Arrays b, Arrays c)
      => (Acc a, Acc b, Acc c)
      -> Acc (a, b, c)
atup3 (a, b, c)
  = Acc $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
atup4 :: (Arrays a, Arrays b, Arrays c, Arrays d)
      => (Acc a, Acc b, Acc c, Acc d)
      -> Acc (a, b, c, d)
atup4 (a, b, c, d)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
atup5 :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e)
      => (Acc a, Acc b, Acc c, Acc d, Acc e)
      -> Acc (a, b, c, d, e)
atup5 (a, b, c, d, e)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
atup6 :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f)
      => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f)
      -> Acc (a, b, c, d, e, f)
atup6 (a, b, c, d, e, f)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
atup7 :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g)
      => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g)
      -> Acc (a, b, c, d, e, f, g)
atup7 (a, b, c, d, e, f, g)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
atup8 :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h)
      => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h)
      -> Acc (a, b, c, d, e, f, g, h)
atup8 (a, b, c, d, e, f, g, h)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
            `SnocAtup` h
atup9 :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i)
      => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i)
      -> Acc (a, b, c, d, e, f, g, h, i)
atup9 (a, b, c, d, e, f, g, h, i)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
            `SnocAtup` h
            `SnocAtup` i
atup10 :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j)
       => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j)
       -> Acc (a, b, c, d, e, f, g, h, i, j)
atup10 (a, b, c, d, e, f, g, h, i, j)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
            `SnocAtup` h
            `SnocAtup` i
            `SnocAtup` j
atup11 :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j, Arrays k)
       => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k)
       -> Acc (a, b, c, d, e, f, g, h, i, j, k)
atup11 (a, b, c, d, e, f, g, h, i, j, k)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
            `SnocAtup` h
            `SnocAtup` i
            `SnocAtup` j
            `SnocAtup` k
atup12 :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j, Arrays k, Arrays l)
       => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l)
       -> Acc (a, b, c, d, e, f, g, h, i, j, k, l)
atup12 (a, b, c, d, e, f, g, h, i, j, k, l)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
            `SnocAtup` h
            `SnocAtup` i
            `SnocAtup` j
            `SnocAtup` k
            `SnocAtup` l
atup13 :: (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)
       => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l, Acc m)
       -> Acc (a, b, c, d, e, f, g, h, i, j, k, l, m)
atup13 (a, b, c, d, e, f, g, h, i, j, k, l, m)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
            `SnocAtup` h
            `SnocAtup` i
            `SnocAtup` j
            `SnocAtup` k
            `SnocAtup` l
            `SnocAtup` m
atup14 :: (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)
       => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l, Acc m, Acc n)
       -> Acc (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
atup14 (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
            `SnocAtup` h
            `SnocAtup` i
            `SnocAtup` j
            `SnocAtup` k
            `SnocAtup` l
            `SnocAtup` m
            `SnocAtup` n
atup15 :: (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)
       => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l, Acc m, Acc n, Acc o)
       -> Acc (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
atup15 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
            `SnocAtup` h
            `SnocAtup` i
            `SnocAtup` j
            `SnocAtup` k
            `SnocAtup` l
            `SnocAtup` m
            `SnocAtup` n
            `SnocAtup` o
atup16 :: (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 p)
       => (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l, Acc m, Acc n, Acc o, Acc p)
       -> Acc (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
atup16 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
  = Acc
  $ Atuple
  $ NilAtup `SnocAtup` a
            `SnocAtup` b
            `SnocAtup` c
            `SnocAtup` d
            `SnocAtup` e
            `SnocAtup` f
            `SnocAtup` g
            `SnocAtup` h
            `SnocAtup` i
            `SnocAtup` j
            `SnocAtup` k
            `SnocAtup` l
            `SnocAtup` m
            `SnocAtup` n
            `SnocAtup` o
            `SnocAtup` p
unatup2 :: (Arrays a, Arrays b)
        => Acc (a, b)
        -> (Acc a, Acc b)
unatup2 e =
  ( Acc $ tix1 `Aprj` e
  , Acc $ tix0 `Aprj` e )
unatup3 :: (Arrays a, Arrays b, Arrays c)
        => Acc (a, b, c)
        -> (Acc a, Acc b, Acc c)
unatup3 e =
  ( Acc $ tix2 `Aprj` e
  , Acc $ tix1 `Aprj` e
  , Acc $ tix0 `Aprj` e )
unatup4
    :: (Arrays a, Arrays b, Arrays c, Arrays d)
    => Acc (a, b, c, d)
    -> (Acc a, Acc b, Acc c, Acc d)
unatup4 e =
  ( Acc $ tix3 `Aprj` e
  , Acc $ tix2 `Aprj` e
  , Acc $ tix1 `Aprj` e
  , Acc $ tix0 `Aprj` e )
unatup5
    :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e)
    => Acc (a, b, c, d, e)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e)
unatup5 e =
  ( Acc $ tix4 `Aprj` e
  , Acc $ tix3 `Aprj` e
  , Acc $ tix2 `Aprj` e
  , Acc $ tix1 `Aprj` e
  , Acc $ tix0 `Aprj` e )
unatup6
    :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f)
    => Acc (a, b, c, d, e, f)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f)
unatup6 e =
  ( Acc $ tix5 `Aprj` e
  , Acc $ tix4 `Aprj` e
  , Acc $ tix3 `Aprj` e
  , Acc $ tix2 `Aprj` e
  , Acc $ tix1 `Aprj` e
  , Acc $ tix0 `Aprj` e )
unatup7
    :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g)
    => Acc (a, b, c, d, e, f, g)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g)
unatup7 e =
  ( Acc $ tix6 `Aprj` e
  , Acc $ tix5 `Aprj` e
  , Acc $ tix4 `Aprj` e
  , Acc $ tix3 `Aprj` e
  , Acc $ tix2 `Aprj` e
  , Acc $ tix1 `Aprj` e
  , Acc $ tix0 `Aprj` e )
unatup8
    :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h)
    => Acc (a, b, c, d, e, f, g, h)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h)
unatup8 e =
  ( Acc $ tix7 `Aprj` e
  , Acc $ tix6 `Aprj` e
  , Acc $ tix5 `Aprj` e
  , Acc $ tix4 `Aprj` e
  , Acc $ tix3 `Aprj` e
  , Acc $ tix2 `Aprj` e
  , Acc $ tix1 `Aprj` e
  , Acc $ tix0 `Aprj` e )
unatup9
    :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i)
    => Acc (a, b, c, d, e, f, g, h, i)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i)
unatup9 e =
  ( Acc $ tix8 `Aprj` e
  , Acc $ tix7 `Aprj` e
  , Acc $ tix6 `Aprj` e
  , Acc $ tix5 `Aprj` e
  , Acc $ tix4 `Aprj` e
  , Acc $ tix3 `Aprj` e
  , Acc $ tix2 `Aprj` e
  , Acc $ tix1 `Aprj` e
  , Acc $ tix0 `Aprj` e )
unatup10
    :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j)
    => Acc (a, b, c, d, e, f, g, h, i, j)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j)
unatup10 e =
  ( Acc $ tix9 `Aprj` e
  , Acc $ tix8 `Aprj` e
  , Acc $ tix7 `Aprj` e
  , Acc $ tix6 `Aprj` e
  , Acc $ tix5 `Aprj` e
  , Acc $ tix4 `Aprj` e
  , Acc $ tix3 `Aprj` e
  , Acc $ tix2 `Aprj` e
  , Acc $ tix1 `Aprj` e
  , Acc $ tix0 `Aprj` e )
unatup11
    :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j, Arrays k)
    => Acc (a, b, c, d, e, f, g, h, i, j, k)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k)
unatup11 e =
  ( Acc $ tix10 `Aprj` e
  , Acc $ tix9  `Aprj` e
  , Acc $ tix8  `Aprj` e
  , Acc $ tix7  `Aprj` e
  , Acc $ tix6  `Aprj` e
  , Acc $ tix5  `Aprj` e
  , Acc $ tix4  `Aprj` e
  , Acc $ tix3  `Aprj` e
  , Acc $ tix2  `Aprj` e
  , Acc $ tix1  `Aprj` e
  , Acc $ tix0  `Aprj` e )
unatup12
    :: (Arrays a, Arrays b, Arrays c, Arrays d, Arrays e, Arrays f, Arrays g, Arrays h, Arrays i, Arrays j, Arrays k, Arrays l)
    => Acc (a, b, c, d, e, f, g, h, i, j, k, l)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l)
unatup12 e =
  ( Acc $ tix11 `Aprj` e
  , Acc $ tix10 `Aprj` e
  , Acc $ tix9  `Aprj` e
  , Acc $ tix8  `Aprj` e
  , Acc $ tix7  `Aprj` e
  , Acc $ tix6  `Aprj` e
  , Acc $ tix5  `Aprj` e
  , Acc $ tix4  `Aprj` e
  , Acc $ tix3  `Aprj` e
  , Acc $ tix2  `Aprj` e
  , Acc $ tix1  `Aprj` e
  , Acc $ tix0  `Aprj` e )
unatup13
    :: (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)
    => Acc (a, b, c, d, e, f, g, h, i, j, k, l, m)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l, Acc m)
unatup13 e =
  ( Acc $ tix12 `Aprj` e
  , Acc $ tix11 `Aprj` e
  , Acc $ tix10 `Aprj` e
  , Acc $ tix9  `Aprj` e
  , Acc $ tix8  `Aprj` e
  , Acc $ tix7  `Aprj` e
  , Acc $ tix6  `Aprj` e
  , Acc $ tix5  `Aprj` e
  , Acc $ tix4  `Aprj` e
  , Acc $ tix3  `Aprj` e
  , Acc $ tix2  `Aprj` e
  , Acc $ tix1  `Aprj` e
  , Acc $ tix0  `Aprj` e )
unatup14
    :: (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)
    => Acc (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l, Acc m, Acc n)
unatup14 e =
  ( Acc $ tix13 `Aprj` e
  , Acc $ tix12 `Aprj` e
  , Acc $ tix11 `Aprj` e
  , Acc $ tix10 `Aprj` e
  , Acc $ tix9  `Aprj` e
  , Acc $ tix8  `Aprj` e
  , Acc $ tix7  `Aprj` e
  , Acc $ tix6  `Aprj` e
  , Acc $ tix5  `Aprj` e
  , Acc $ tix4  `Aprj` e
  , Acc $ tix3  `Aprj` e
  , Acc $ tix2  `Aprj` e
  , Acc $ tix1  `Aprj` e
  , Acc $ tix0  `Aprj` e )
unatup15
    :: (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)
    => Acc (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l, Acc m, Acc n, Acc o)
unatup15 e =
  ( Acc $ tix14 `Aprj` e
  , Acc $ tix13 `Aprj` e
  , Acc $ tix12 `Aprj` e
  , Acc $ tix11 `Aprj` e
  , Acc $ tix10 `Aprj` e
  , Acc $ tix9  `Aprj` e
  , Acc $ tix8  `Aprj` e
  , Acc $ tix7  `Aprj` e
  , Acc $ tix6  `Aprj` e
  , Acc $ tix5  `Aprj` e
  , Acc $ tix4  `Aprj` e
  , Acc $ tix3  `Aprj` e
  , Acc $ tix2  `Aprj` e
  , Acc $ tix1  `Aprj` e
  , Acc $ tix0  `Aprj` e )
unatup16
    :: (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 p)
    => Acc (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
    -> (Acc a, Acc b, Acc c, Acc d, Acc e, Acc f, Acc g, Acc h, Acc i, Acc j, Acc k, Acc l, Acc m, Acc n, Acc o, Acc p)
unatup16 e =
  ( Acc $ tix15 `Aprj` e
  , Acc $ tix14 `Aprj` e
  , Acc $ tix13 `Aprj` e
  , Acc $ tix12 `Aprj` e
  , Acc $ tix11 `Aprj` e
  , Acc $ tix10 `Aprj` e
  , Acc $ tix9  `Aprj` e
  , Acc $ tix8  `Aprj` e
  , Acc $ tix7  `Aprj` e
  , Acc $ tix6  `Aprj` e
  , Acc $ tix5  `Aprj` e
  , Acc $ tix4  `Aprj` e
  , Acc $ tix3  `Aprj` e
  , Acc $ tix2  `Aprj` e
  , Acc $ tix1  `Aprj` e
  , Acc $ tix0  `Aprj` e )
newtype Boundary t = Boundary (PreBoundary Acc Exp t)
data PreBoundary acc exp t where
  Clamp     :: PreBoundary acc exp t
  Mirror    :: PreBoundary acc exp t
  Wrap      :: PreBoundary acc exp t
  Constant  :: Elt e
            => e
            -> PreBoundary acc exp (Array sh e)
  Function  :: (Shape sh, Elt e)
            => (Exp sh -> exp e)
            -> PreBoundary acc exp (Array sh e)
class (Elt (StencilRepr sh stencil), AST.Stencil sh a (StencilRepr sh stencil)) => Stencil sh a stencil where
  type StencilRepr sh stencil :: *
  stencilPrj ::  sh
             ->  a
             -> Exp (StencilRepr sh stencil)
             -> stencil
instance Elt e => Stencil DIM1 e (Exp e, Exp e, Exp e) where
  type StencilRepr DIM1 (Exp e, Exp e, Exp e)
    = (e, e, e)
  stencilPrj _ _ s = (Exp $ Prj tix2 s,
                      Exp $ Prj tix1 s,
                      Exp $ Prj tix0 s)
instance Elt e => Stencil DIM1 e (Exp e, Exp e, Exp e, Exp e, Exp e) where
  type StencilRepr DIM1 (Exp e, Exp e, Exp e, Exp e, Exp e)
    = (e, e, e, e, e)
  stencilPrj _ _ s = (Exp $ Prj tix4 s,
                      Exp $ Prj tix3 s,
                      Exp $ Prj tix2 s,
                      Exp $ Prj tix1 s,
                      Exp $ Prj tix0 s)
instance Elt e => Stencil DIM1 e (Exp e, Exp e, Exp e, Exp e, Exp e, Exp e, Exp e) where
  type StencilRepr DIM1 (Exp e, Exp e, Exp e, Exp e, Exp e, Exp e, Exp e)
    = (e, e, e, e, e, e, e)
  stencilPrj _ _ s = (Exp $ Prj tix6 s,
                      Exp $ Prj tix5 s,
                      Exp $ Prj tix4 s,
                      Exp $ Prj tix3 s,
                      Exp $ Prj tix2 s,
                      Exp $ Prj tix1 s,
                      Exp $ Prj tix0 s)
instance Elt e => Stencil DIM1 e (Exp e, Exp e, Exp e, Exp e, Exp e, Exp e, Exp e, Exp e, Exp e)
  where
  type StencilRepr DIM1 (Exp e, Exp e, Exp e, Exp e, Exp e, Exp e, Exp e, Exp e, Exp e)
    = (e, e, e, e, e, e, e, e, e)
  stencilPrj _ _ s = (Exp $ Prj tix8 s,
                      Exp $ Prj tix7 s,
                      Exp $ Prj tix6 s,
                      Exp $ Prj tix5 s,
                      Exp $ Prj tix4 s,
                      Exp $ Prj tix3 s,
                      Exp $ Prj tix2 s,
                      Exp $ Prj tix1 s,
                      Exp $ Prj tix0 s)
instance (Stencil (sh:.Int) a row2,
          Stencil (sh:.Int) a row1,
          Stencil (sh:.Int) a row0) => Stencil (sh:.Int:.Int) a (row2, row1, row0) where
  type StencilRepr (sh:.Int:.Int) (row2, row1, row0)
    = (StencilRepr (sh:.Int) row2, StencilRepr (sh:.Int) row1, StencilRepr (sh:.Int) row0)
  stencilPrj _ a s = (stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix2 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix1 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix0 s))
instance (Stencil (sh:.Int) a row1,
          Stencil (sh:.Int) a row2,
          Stencil (sh:.Int) a row3,
          Stencil (sh:.Int) a row4,
          Stencil (sh:.Int) a row5) => Stencil (sh:.Int:.Int) a (row1, row2, row3, row4, row5) where
  type StencilRepr (sh:.Int:.Int) (row1, row2, row3, row4, row5)
    = (StencilRepr (sh:.Int) row1, StencilRepr (sh:.Int) row2, StencilRepr (sh:.Int) row3,
       StencilRepr (sh:.Int) row4, StencilRepr (sh:.Int) row5)
  stencilPrj _ a s = (stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix4 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix3 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix2 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix1 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix0 s))
instance (Stencil (sh:.Int) a row1,
          Stencil (sh:.Int) a row2,
          Stencil (sh:.Int) a row3,
          Stencil (sh:.Int) a row4,
          Stencil (sh:.Int) a row5,
          Stencil (sh:.Int) a row6,
          Stencil (sh:.Int) a row7)
  => Stencil (sh:.Int:.Int) a (row1, row2, row3, row4, row5, row6, row7) where
  type StencilRepr (sh:.Int:.Int) (row1, row2, row3, row4, row5, row6, row7)
    = (StencilRepr (sh:.Int) row1, StencilRepr (sh:.Int) row2, StencilRepr (sh:.Int) row3,
       StencilRepr (sh:.Int) row4, StencilRepr (sh:.Int) row5, StencilRepr (sh:.Int) row6,
       StencilRepr (sh:.Int) row7)
  stencilPrj _ a s = (stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix6 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix5 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix4 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix3 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix2 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix1 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix0 s))
instance (Stencil (sh:.Int) a row1,
          Stencil (sh:.Int) a row2,
          Stencil (sh:.Int) a row3,
          Stencil (sh:.Int) a row4,
          Stencil (sh:.Int) a row5,
          Stencil (sh:.Int) a row6,
          Stencil (sh:.Int) a row7,
          Stencil (sh:.Int) a row8,
          Stencil (sh:.Int) a row9)
  => Stencil (sh:.Int:.Int) a (row1, row2, row3, row4, row5, row6, row7, row8, row9) where
  type StencilRepr (sh:.Int:.Int) (row1, row2, row3, row4, row5, row6, row7, row8, row9)
    = (StencilRepr (sh:.Int) row1, StencilRepr (sh:.Int) row2, StencilRepr (sh:.Int) row3,
       StencilRepr (sh:.Int) row4, StencilRepr (sh:.Int) row5, StencilRepr (sh:.Int) row6,
       StencilRepr (sh:.Int) row7, StencilRepr (sh:.Int) row8, StencilRepr (sh:.Int) row9)
  stencilPrj _ a s = (stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix8 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix7 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix6 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix5 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix4 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix3 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix2 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix1 s),
                      stencilPrj (undefined::(sh:.Int)) a (Exp $ Prj tix0 s))
tix0 :: TupleIdx (t, s0) s0
tix0 = ZeroTupIdx
tix1 :: TupleIdx ((t, s1), s0) s1
tix1 = SuccTupIdx tix0
tix2 :: TupleIdx (((t, s2), s1), s0) s2
tix2 = SuccTupIdx tix1
tix3 :: TupleIdx ((((t, s3), s2), s1), s0) s3
tix3 = SuccTupIdx tix2
tix4 :: TupleIdx (((((t, s4), s3), s2), s1), s0) s4
tix4 = SuccTupIdx tix3
tix5 :: TupleIdx ((((((t, s5), s4), s3), s2), s1), s0) s5
tix5 = SuccTupIdx tix4
tix6 :: TupleIdx (((((((t, s6), s5), s4), s3), s2), s1), s0) s6
tix6 = SuccTupIdx tix5
tix7 :: TupleIdx ((((((((t, s7), s6), s5), s4), s3), s2), s1), s0) s7
tix7 = SuccTupIdx tix6
tix8 :: TupleIdx (((((((((t, s8), s7), s6), s5), s4), s3), s2), s1), s0) s8
tix8 = SuccTupIdx tix7
tix9 :: TupleIdx ((((((((((t, s9), s8), s7), s6), s5), s4), s3), s2), s1), s0) s9
tix9 = SuccTupIdx tix8
tix10 :: TupleIdx (((((((((((t, s10), s9), s8), s7), s6), s5), s4), s3), s2), s1), s0) s10
tix10 = SuccTupIdx tix9
tix11 :: TupleIdx ((((((((((((t, s11), s10), s9), s8), s7), s6), s5), s4), s3), s2), s1), s0) s11
tix11 = SuccTupIdx tix10
tix12 :: TupleIdx (((((((((((((t, s12), s11), s10), s9), s8), s7), s6), s5), s4), s3), s2), s1), s0) s12
tix12 = SuccTupIdx tix11
tix13 :: TupleIdx ((((((((((((((t, s13), s12), s11), s10), s9), s8), s7), s6), s5), s4), s3), s2), s1), s0) s13
tix13 = SuccTupIdx tix12
tix14 :: TupleIdx (((((((((((((((t, s14), s13), s12), s11), s10), s9), s8), s7), s6), s5), s4), s3), s2), s1), s0) s14
tix14 = SuccTupIdx tix13
tix15 :: TupleIdx ((((((((((((((((t, s15), s14), s13), s12), s11), s10), s9), s8), s7), s6), s5), s4), s3), s2), s1), s0) s15
tix15 = SuccTupIdx tix14
constant :: Elt t => t -> Exp t
constant = Exp . Const
undef :: Elt t => Exp t
undef = Exp Undef
tup2 :: (Elt a, Elt b) => (Exp a, Exp b) -> Exp (a, b)
tup2 (a, b)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
tup3 :: (Elt a, Elt b, Elt c)
     => (Exp a, Exp b, Exp c)
     -> Exp (a, b, c)
tup3 (a, b, c)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
tup4 :: (Elt a, Elt b, Elt c, Elt d)
     => (Exp a, Exp b, Exp c, Exp d)
     -> Exp (a, b, c, d)
tup4 (a, b, c, d)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
tup5 :: (Elt a, Elt b, Elt c, Elt d, Elt e)
     => (Exp a, Exp b, Exp c, Exp d, Exp e)
     -> Exp (a, b, c, d, e)
tup5 (a, b, c, d, e)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
tup6 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f)
     => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f)
     -> Exp (a, b, c, d, e, f)
tup6 (a, b, c, d, e, f)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
tup7 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g)
     => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g)
     -> Exp (a, b, c, d, e, f, g)
tup7 (a, b, c, d, e, f, g)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
tup8 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h)
     => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h)
     -> Exp (a, b, c, d, e, f, g, h)
tup8 (a, b, c, d, e, f, g, h)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
           `SnocTup` h
tup9 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i)
     => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i)
     -> Exp (a, b, c, d, e, f, g, h, i)
tup9 (a, b, c, d, e, f, g, h, i)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
           `SnocTup` h
           `SnocTup` i
tup10 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j)
      => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j)
      -> Exp (a, b, c, d, e, f, g, h, i, j)
tup10 (a, b, c, d, e, f, g, h, i, j)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
           `SnocTup` h
           `SnocTup` i
           `SnocTup` j
tup11 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j, Elt k)
      => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k)
      -> Exp (a, b, c, d, e, f, g, h, i, j, k)
tup11 (a, b, c, d, e, f, g, h, i, j, k)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
           `SnocTup` h
           `SnocTup` i
           `SnocTup` j
           `SnocTup` k
tup12 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j, Elt k, Elt l)
      => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l)
      -> Exp (a, b, c, d, e, f, g, h, i, j, k, l)
tup12 (a, b, c, d, e, f, g, h, i, j, k, l)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
           `SnocTup` h
           `SnocTup` i
           `SnocTup` j
           `SnocTup` k
           `SnocTup` l
tup13 :: (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)
      => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l, Exp m)
      -> Exp (a, b, c, d, e, f, g, h, i, j, k, l, m)
tup13 (a, b, c, d, e, f, g, h, i, j, k, l, m)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
           `SnocTup` h
           `SnocTup` i
           `SnocTup` j
           `SnocTup` k
           `SnocTup` l
           `SnocTup` m
tup14 :: (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)
      => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l, Exp m, Exp n)
      -> Exp (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
tup14 (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
           `SnocTup` h
           `SnocTup` i
           `SnocTup` j
           `SnocTup` k
           `SnocTup` l
           `SnocTup` m
           `SnocTup` n
tup15 :: (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)
      => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l, Exp m, Exp n, Exp o)
      -> Exp (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
tup15 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
           `SnocTup` h
           `SnocTup` i
           `SnocTup` j
           `SnocTup` k
           `SnocTup` l
           `SnocTup` m
           `SnocTup` n
           `SnocTup` o
tup16 :: (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 p)
      => (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l, Exp m, Exp n, Exp o, Exp p)
      -> Exp (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
tup16 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
  = Exp
  $ Tuple
  $ NilTup `SnocTup` a
           `SnocTup` b
           `SnocTup` c
           `SnocTup` d
           `SnocTup` e
           `SnocTup` f
           `SnocTup` g
           `SnocTup` h
           `SnocTup` i
           `SnocTup` j
           `SnocTup` k
           `SnocTup` l
           `SnocTup` m
           `SnocTup` n
           `SnocTup` o
           `SnocTup` p
untup2 :: (Elt a, Elt b) => Exp (a, b) -> (Exp a, Exp b)
untup2 e =
  ( Exp $ tix1 `Prj` e
  , Exp $ tix0 `Prj` e )
untup3 :: (Elt a, Elt b, Elt c) => Exp (a, b, c) -> (Exp a, Exp b, Exp c)
untup3 e =
  ( Exp $ tix2 `Prj` e
  , Exp $ tix1 `Prj` e
  , Exp $ tix0 `Prj` e )
untup4 :: (Elt a, Elt b, Elt c, Elt d)
       => Exp (a, b, c, d)
       -> (Exp a, Exp b, Exp c, Exp d)
untup4 e =
  ( Exp $ tix3 `Prj` e
  , Exp $ tix2 `Prj` e
  , Exp $ tix1 `Prj` e
  , Exp $ tix0 `Prj` e )
untup5 :: (Elt a, Elt b, Elt c, Elt d, Elt e)
       => Exp (a, b, c, d, e)
       -> (Exp a, Exp b, Exp c, Exp d, Exp e)
untup5 e =
  ( Exp $ tix4 `Prj` e
  , Exp $ tix3 `Prj` e
  , Exp $ tix2 `Prj` e
  , Exp $ tix1 `Prj` e
  , Exp $ tix0 `Prj` e )
untup6 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f)
       => Exp (a, b, c, d, e, f)
       -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f)
untup6 e =
  ( Exp $ tix5 `Prj` e
  , Exp $ tix4 `Prj` e
  , Exp $ tix3 `Prj` e
  , Exp $ tix2 `Prj` e
  , Exp $ tix1 `Prj` e
  , Exp $ tix0 `Prj` e )
untup7 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g)
       => Exp (a, b, c, d, e, f, g)
       -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g)
untup7 e =
  ( Exp $ tix6 `Prj` e
  , Exp $ tix5 `Prj` e
  , Exp $ tix4 `Prj` e
  , Exp $ tix3 `Prj` e
  , Exp $ tix2 `Prj` e
  , Exp $ tix1 `Prj` e
  , Exp $ tix0 `Prj` e )
untup8 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h)
       => Exp (a, b, c, d, e, f, g, h)
       -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h)
untup8 e =
  ( Exp $ tix7 `Prj` e
  , Exp $ tix6 `Prj` e
  , Exp $ tix5 `Prj` e
  , Exp $ tix4 `Prj` e
  , Exp $ tix3 `Prj` e
  , Exp $ tix2 `Prj` e
  , Exp $ tix1 `Prj` e
  , Exp $ tix0 `Prj` e )
untup9 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i)
       => Exp (a, b, c, d, e, f, g, h, i)
       -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i)
untup9 e =
  ( Exp $ tix8 `Prj` e
  , Exp $ tix7 `Prj` e
  , Exp $ tix6 `Prj` e
  , Exp $ tix5 `Prj` e
  , Exp $ tix4 `Prj` e
  , Exp $ tix3 `Prj` e
  , Exp $ tix2 `Prj` e
  , Exp $ tix1 `Prj` e
  , Exp $ tix0 `Prj` e )
untup10 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j)
        => Exp (a, b, c, d, e, f, g, h, i, j)
        -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j)
untup10 e =
  ( Exp $ tix9 `Prj` e
  , Exp $ tix8 `Prj` e
  , Exp $ tix7 `Prj` e
  , Exp $ tix6 `Prj` e
  , Exp $ tix5 `Prj` e
  , Exp $ tix4 `Prj` e
  , Exp $ tix3 `Prj` e
  , Exp $ tix2 `Prj` e
  , Exp $ tix1 `Prj` e
  , Exp $ tix0 `Prj` e )
untup11 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j, Elt k)
        => Exp (a, b, c, d, e, f, g, h, i, j, k)
        -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k)
untup11 e =
  ( Exp $ tix10 `Prj` e
  , Exp $ tix9  `Prj` e
  , Exp $ tix8  `Prj` e
  , Exp $ tix7  `Prj` e
  , Exp $ tix6  `Prj` e
  , Exp $ tix5  `Prj` e
  , Exp $ tix4  `Prj` e
  , Exp $ tix3  `Prj` e
  , Exp $ tix2  `Prj` e
  , Exp $ tix1  `Prj` e
  , Exp $ tix0  `Prj` e )
untup12 :: (Elt a, Elt b, Elt c, Elt d, Elt e, Elt f, Elt g, Elt h, Elt i, Elt j, Elt k, Elt l)
        => Exp (a, b, c, d, e, f, g, h, i, j, k, l)
        -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l)
untup12 e =
  ( Exp $ tix11 `Prj` e
  , Exp $ tix10 `Prj` e
  , Exp $ tix9  `Prj` e
  , Exp $ tix8  `Prj` e
  , Exp $ tix7  `Prj` e
  , Exp $ tix6  `Prj` e
  , Exp $ tix5  `Prj` e
  , Exp $ tix4  `Prj` e
  , Exp $ tix3  `Prj` e
  , Exp $ tix2  `Prj` e
  , Exp $ tix1  `Prj` e
  , Exp $ tix0  `Prj` e )
untup13 :: (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)
        => Exp (a, b, c, d, e, f, g, h, i, j, k, l, m)
        -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l, Exp m)
untup13 e =
  ( Exp $ tix12 `Prj` e
  , Exp $ tix11 `Prj` e
  , Exp $ tix10 `Prj` e
  , Exp $ tix9  `Prj` e
  , Exp $ tix8  `Prj` e
  , Exp $ tix7  `Prj` e
  , Exp $ tix6  `Prj` e
  , Exp $ tix5  `Prj` e
  , Exp $ tix4  `Prj` e
  , Exp $ tix3  `Prj` e
  , Exp $ tix2  `Prj` e
  , Exp $ tix1  `Prj` e
  , Exp $ tix0  `Prj` e )
untup14 :: (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)
        => Exp (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
        -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l, Exp m, Exp n)
untup14 e =
  ( Exp $ tix13 `Prj` e
  , Exp $ tix12 `Prj` e
  , Exp $ tix11 `Prj` e
  , Exp $ tix10 `Prj` e
  , Exp $ tix9  `Prj` e
  , Exp $ tix8  `Prj` e
  , Exp $ tix7  `Prj` e
  , Exp $ tix6  `Prj` e
  , Exp $ tix5  `Prj` e
  , Exp $ tix4  `Prj` e
  , Exp $ tix3  `Prj` e
  , Exp $ tix2  `Prj` e
  , Exp $ tix1  `Prj` e
  , Exp $ tix0  `Prj` e )
untup15 :: (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)
        => Exp (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
        -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l, Exp m, Exp n, Exp o)
untup15 e =
  ( Exp $ tix14 `Prj` e
  , Exp $ tix13 `Prj` e
  , Exp $ tix12 `Prj` e
  , Exp $ tix11 `Prj` e
  , Exp $ tix10 `Prj` e
  , Exp $ tix9  `Prj` e
  , Exp $ tix8  `Prj` e
  , Exp $ tix7  `Prj` e
  , Exp $ tix6  `Prj` e
  , Exp $ tix5  `Prj` e
  , Exp $ tix4  `Prj` e
  , Exp $ tix3  `Prj` e
  , Exp $ tix2  `Prj` e
  , Exp $ tix1  `Prj` e
  , Exp $ tix0  `Prj` e )
untup16 :: (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 p)
        => Exp (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
        -> (Exp a, Exp b, Exp c, Exp d, Exp e, Exp f, Exp g, Exp h, Exp i, Exp j, Exp k, Exp l, Exp m, Exp n, Exp o, Exp p)
untup16 e =
  ( Exp $ tix15 `Prj` e
  , Exp $ tix14 `Prj` e
  , Exp $ tix13 `Prj` e
  , Exp $ tix12 `Prj` e
  , Exp $ tix11 `Prj` e
  , Exp $ tix10 `Prj` e
  , Exp $ tix9  `Prj` e
  , Exp $ tix8  `Prj` e
  , Exp $ tix7  `Prj` e
  , Exp $ tix6  `Prj` e
  , Exp $ tix5  `Prj` e
  , Exp $ tix4  `Prj` e
  , Exp $ tix3  `Prj` e
  , Exp $ tix2  `Prj` e
  , Exp $ tix1  `Prj` e
  , Exp $ tix0  `Prj` e )
mkMinBound :: (Elt t, IsBounded t) => Exp t
mkMinBound = Exp $ PrimConst (PrimMinBound boundedType)
mkMaxBound :: (Elt t, IsBounded t) => Exp t
mkMaxBound = Exp $ PrimConst (PrimMaxBound boundedType)
mkPi :: (Elt r, IsFloating r) => Exp r
mkPi = Exp $ PrimConst (PrimPi floatingType)
mkSin :: (Elt t, IsFloating t) => Exp t -> Exp t
mkSin x = Exp $ PrimSin floatingType `PrimApp` x
mkCos :: (Elt t, IsFloating t) => Exp t -> Exp t
mkCos x = Exp $ PrimCos floatingType `PrimApp` x
mkTan :: (Elt t, IsFloating t) => Exp t -> Exp t
mkTan x = Exp $ PrimTan floatingType `PrimApp` x
mkAsin :: (Elt t, IsFloating t) => Exp t -> Exp t
mkAsin x = Exp $ PrimAsin floatingType `PrimApp` x
mkAcos :: (Elt t, IsFloating t) => Exp t -> Exp t
mkAcos x = Exp $ PrimAcos floatingType `PrimApp` x
mkAtan :: (Elt t, IsFloating t) => Exp t -> Exp t
mkAtan x = Exp $ PrimAtan floatingType `PrimApp` x
mkSinh :: (Elt t, IsFloating t) => Exp t -> Exp t
mkSinh x = Exp $ PrimSinh floatingType `PrimApp` x
mkCosh :: (Elt t, IsFloating t) => Exp t -> Exp t
mkCosh x = Exp $ PrimCosh floatingType `PrimApp` x
mkTanh :: (Elt t, IsFloating t) => Exp t -> Exp t
mkTanh x = Exp $ PrimTanh floatingType `PrimApp` x
mkAsinh :: (Elt t, IsFloating t) => Exp t -> Exp t
mkAsinh x = Exp $ PrimAsinh floatingType `PrimApp` x
mkAcosh :: (Elt t, IsFloating t) => Exp t -> Exp t
mkAcosh x = Exp $ PrimAcosh floatingType `PrimApp` x
mkAtanh :: (Elt t, IsFloating t) => Exp t -> Exp t
mkAtanh x = Exp $ PrimAtanh floatingType `PrimApp` x
mkExpFloating :: (Elt t, IsFloating t) => Exp t -> Exp t
mkExpFloating x = Exp $ PrimExpFloating floatingType `PrimApp` x
mkSqrt :: (Elt t, IsFloating t) => Exp t -> Exp t
mkSqrt x = Exp $ PrimSqrt floatingType `PrimApp` x
mkLog :: (Elt t, IsFloating t) => Exp t -> Exp t
mkLog x = Exp $ PrimLog floatingType `PrimApp` x
mkFPow :: (Elt t, IsFloating t) => Exp t -> Exp t -> Exp t
mkFPow x y = Exp $ PrimFPow floatingType `PrimApp` tup2 (x, y)
mkLogBase :: (Elt t, IsFloating t) => Exp t -> Exp t -> Exp t
mkLogBase x y = Exp $ PrimLogBase floatingType `PrimApp` tup2 (x, y)
mkAdd :: (Elt t, IsNum t) => Exp t -> Exp t -> Exp t
mkAdd x y = Exp $ PrimAdd numType `PrimApp` tup2 (x, y)
mkSub :: (Elt t, IsNum t) => Exp t -> Exp t -> Exp t
mkSub x y = Exp $ PrimSub numType `PrimApp` tup2 (x, y)
mkMul :: (Elt t, IsNum t) => Exp t -> Exp t -> Exp t
mkMul x y = Exp $ PrimMul numType `PrimApp` tup2 (x, y)
mkNeg :: (Elt t, IsNum t) => Exp t -> Exp t
mkNeg x = Exp $ PrimNeg numType `PrimApp` x
mkAbs :: (Elt t, IsNum t) => Exp t -> Exp t
mkAbs x = Exp $ PrimAbs numType `PrimApp` x
mkSig :: (Elt t, IsNum t) => Exp t -> Exp t
mkSig x = Exp $ PrimSig numType `PrimApp` x
mkQuot :: (Elt t, IsIntegral t) => Exp t -> Exp t -> Exp t
mkQuot x y = Exp $ PrimQuot integralType `PrimApp` tup2 (x, y)
mkRem :: (Elt t, IsIntegral t) => Exp t -> Exp t -> Exp t
mkRem x y = Exp $ PrimRem integralType `PrimApp` tup2 (x, y)
mkQuotRem :: (Elt t, IsIntegral t) => Exp t -> Exp t -> (Exp t, Exp t)
mkQuotRem x y = untup2 $ Exp $ PrimQuotRem integralType `PrimApp` tup2 (x ,y)
mkIDiv :: (Elt t, IsIntegral t) => Exp t -> Exp t -> Exp t
mkIDiv x y = Exp $ PrimIDiv integralType `PrimApp` tup2 (x, y)
mkMod :: (Elt t, IsIntegral t) => Exp t -> Exp t -> Exp t
mkMod x y = Exp $ PrimMod integralType `PrimApp` tup2 (x, y)
mkDivMod :: (Elt t, IsIntegral t) => Exp t -> Exp t -> (Exp t, Exp t)
mkDivMod x y = untup2 $ Exp $ PrimDivMod integralType `PrimApp` tup2 (x ,y)
mkBAnd :: (Elt t, IsIntegral t) => Exp t -> Exp t -> Exp t
mkBAnd x y = Exp $ PrimBAnd integralType `PrimApp` tup2 (x, y)
mkBOr :: (Elt t, IsIntegral t) => Exp t -> Exp t -> Exp t
mkBOr x y = Exp $ PrimBOr integralType `PrimApp` tup2 (x, y)
mkBXor :: (Elt t, IsIntegral t) => Exp t -> Exp t -> Exp t
mkBXor x y = Exp $ PrimBXor integralType `PrimApp` tup2 (x, y)
mkBNot :: (Elt t, IsIntegral t) => Exp t -> Exp t
mkBNot x = Exp $ PrimBNot integralType `PrimApp` x
mkBShiftL :: (Elt t, IsIntegral t) => Exp t -> Exp Int -> Exp t
mkBShiftL x i = Exp $ PrimBShiftL integralType `PrimApp` tup2 (x, i)
mkBShiftR :: (Elt t, IsIntegral t) => Exp t -> Exp Int -> Exp t
mkBShiftR x i = Exp $ PrimBShiftR integralType `PrimApp` tup2 (x, i)
mkBRotateL :: (Elt t, IsIntegral t) => Exp t -> Exp Int -> Exp t
mkBRotateL x i = Exp $ PrimBRotateL integralType `PrimApp` tup2 (x, i)
mkBRotateR :: (Elt t, IsIntegral t) => Exp t -> Exp Int -> Exp t
mkBRotateR x i = Exp $ PrimBRotateR integralType `PrimApp` tup2 (x, i)
mkPopCount :: (Elt t, IsIntegral t) => Exp t -> Exp Int
mkPopCount x = Exp $ PrimPopCount integralType `PrimApp` x
mkCountLeadingZeros :: (Elt t, IsIntegral t) => Exp t -> Exp Int
mkCountLeadingZeros x = Exp $ PrimCountLeadingZeros integralType `PrimApp` x
mkCountTrailingZeros :: (Elt t, IsIntegral t) => Exp t -> Exp Int
mkCountTrailingZeros x = Exp $ PrimCountTrailingZeros integralType `PrimApp` x
mkFDiv :: (Elt t, IsFloating t) => Exp t -> Exp t -> Exp t
mkFDiv x y = Exp $ PrimFDiv floatingType `PrimApp` tup2 (x, y)
mkRecip :: (Elt t, IsFloating t) => Exp t -> Exp t
mkRecip x = Exp $ PrimRecip floatingType `PrimApp` x
mkTruncate :: (Elt a, Elt b, IsFloating a, IsIntegral b) => Exp a -> Exp b
mkTruncate x = Exp $ PrimTruncate floatingType integralType `PrimApp` x
mkRound :: (Elt a, Elt b, IsFloating a, IsIntegral b) => Exp a -> Exp b
mkRound x = Exp $ PrimRound floatingType integralType `PrimApp` x
mkFloor :: (Elt a, Elt b, IsFloating a, IsIntegral b) => Exp a -> Exp b
mkFloor x = Exp $ PrimFloor floatingType integralType `PrimApp` x
mkCeiling :: (Elt a, Elt b, IsFloating a, IsIntegral b) => Exp a -> Exp b
mkCeiling x = Exp $ PrimCeiling floatingType integralType `PrimApp` x
mkAtan2 :: (Elt t, IsFloating t) => Exp t -> Exp t -> Exp t
mkAtan2 x y = Exp $ PrimAtan2 floatingType `PrimApp` tup2 (x, y)
mkIsNaN :: (Elt t, IsFloating t) => Exp t -> Exp Bool
mkIsNaN x = Exp $ PrimIsNaN floatingType `PrimApp` x
mkIsInfinite :: (Elt t, IsFloating t) => Exp t -> Exp Bool
mkIsInfinite x = Exp $ PrimIsInfinite floatingType `PrimApp` x
mkLt :: (Elt t, IsSingle t) => Exp t -> Exp t -> Exp Bool
mkLt x y = Exp $ PrimLt singleType `PrimApp` tup2 (x, y)
mkGt :: (Elt t, IsSingle t) => Exp t -> Exp t -> Exp Bool
mkGt x y = Exp $ PrimGt singleType `PrimApp` tup2 (x, y)
mkLtEq :: (Elt t, IsSingle t) => Exp t -> Exp t -> Exp Bool
mkLtEq x y = Exp $ PrimLtEq singleType `PrimApp` tup2 (x, y)
mkGtEq :: (Elt t, IsSingle t) => Exp t -> Exp t -> Exp Bool
mkGtEq x y = Exp $ PrimGtEq singleType `PrimApp` tup2 (x, y)
mkEq :: (Elt t, IsSingle t) => Exp t -> Exp t -> Exp Bool
mkEq x y = Exp $ PrimEq singleType `PrimApp` tup2 (x, y)
mkNEq :: (Elt t, IsSingle t) => Exp t -> Exp t -> Exp Bool
mkNEq x y = Exp $ PrimNEq singleType `PrimApp` tup2 (x, y)
mkMax :: (Elt t, IsSingle t) => Exp t -> Exp t -> Exp t
mkMax x y = Exp $ PrimMax singleType `PrimApp` tup2 (x, y)
mkMin :: (Elt t, IsSingle t) => Exp t -> Exp t -> Exp t
mkMin x y = Exp $ PrimMin singleType `PrimApp` tup2 (x, y)
mkLAnd :: Exp Bool -> Exp Bool -> Exp Bool
mkLAnd x y = Exp $ PrimLAnd `PrimApp` tup2 (x, y)
mkLOr :: Exp Bool -> Exp Bool -> Exp Bool
mkLOr x y = Exp $ PrimLOr `PrimApp` tup2 (x, y)
mkLNot :: Exp Bool -> Exp Bool
mkLNot x = Exp $ PrimLNot `PrimApp` x
mkOrd :: Exp Char -> Exp Int
mkOrd x = Exp $ PrimOrd `PrimApp` x
mkChr :: Exp Int -> Exp Char
mkChr x = Exp $ PrimChr `PrimApp` x
mkFromIntegral :: (Elt a, Elt b, IsIntegral a, IsNum b) => Exp a -> Exp b
mkFromIntegral x = Exp $ PrimFromIntegral integralType numType `PrimApp` x
mkToFloating :: (Elt a, Elt b, IsNum a, IsFloating b) => Exp a -> Exp b
mkToFloating x = Exp $ PrimToFloating numType floatingType `PrimApp` x
mkBoolToInt :: Exp Bool -> Exp Int
mkBoolToInt b = Exp $ PrimBoolToInt `PrimApp` b
mkBitcast :: (Elt a, Elt b, IsScalar (EltRepr a), IsScalar (EltRepr b), BitSizeEq (EltRepr a) (EltRepr b)) => Exp a -> Exp b
mkBitcast = mkUnsafeCoerce
mkUnsafeCoerce :: (Elt a, Elt b) => Exp a -> Exp b
mkUnsafeCoerce = Exp . Coerce
infixr 0 $$
($$) :: (b -> a) -> (c -> d -> b) -> c -> d -> a
(f $$ g) x y = f (g x y)
infixr 0 $$$
($$$) :: (b -> a) -> (c -> d -> e -> b) -> c -> d -> e -> a
(f $$$ g) x y z = f (g x y z)
infixr 0 $$$$
($$$$) :: (b -> a) -> (c -> d -> e -> f -> b) -> c -> d -> e -> f -> a
(f $$$$ g) x y z u = f (g x y z u)
infixr 0 $$$$$
($$$$$) :: (b -> a) -> (c -> d -> e -> f -> g -> b) -> c -> d -> e -> f -> g-> a
(f $$$$$ g) x y z u v = f (g x y z u v)
showPreAccOp :: forall acc exp arrs. PreAcc acc exp arrs -> String
showPreAccOp (Atag i)           = "Atag " ++ show i
showPreAccOp (Use a)            = "Use "  ++ showArrays a
showPreAccOp Pipe{}             = "Pipe"
showPreAccOp Acond{}            = "Acond"
showPreAccOp Awhile{}           = "Awhile"
showPreAccOp Atuple{}           = "Atuple"
showPreAccOp Aprj{}             = "Aprj"
showPreAccOp Unit{}             = "Unit"
showPreAccOp Generate{}         = "Generate"
showPreAccOp Reshape{}          = "Reshape"
showPreAccOp Replicate{}        = "Replicate"
showPreAccOp Slice{}            = "Slice"
showPreAccOp Map{}              = "Map"
showPreAccOp ZipWith{}          = "ZipWith"
showPreAccOp Fold{}             = "Fold"
showPreAccOp Fold1{}            = "Fold1"
showPreAccOp FoldSeg{}          = "FoldSeg"
showPreAccOp Fold1Seg{}         = "Fold1Seg"
showPreAccOp Scanl{}            = "Scanl"
showPreAccOp Scanl'{}           = "Scanl'"
showPreAccOp Scanl1{}           = "Scanl1"
showPreAccOp Scanr{}            = "Scanr"
showPreAccOp Scanr'{}           = "Scanr'"
showPreAccOp Scanr1{}           = "Scanr1"
showPreAccOp Permute{}          = "Permute"
showPreAccOp Backpermute{}      = "Backpermute"
showPreAccOp Stencil{}          = "Stencil"
showPreAccOp Stencil2{}         = "Stencil2"
showPreAccOp Aforeign{}         = "Aforeign"
showArrays :: forall arrs. Arrays arrs => arrs -> String
showArrays = display . collect (arrays (undefined::arrs)) . fromArr
  where
    collect :: ArraysR a -> a -> [String]
    collect ArraysRunit         _        = []
    collect ArraysRarray        arr      = [showShortendArr arr]
    collect (ArraysRpair r1 r2) (a1, a2) = collect r1 a1 ++ collect r2 a2
    
    display []  = []
    display [x] = x
    display xs  = "(" ++ intercalate ", " xs ++ ")"
showShortendArr :: Elt e => Array sh e -> String
showShortendArr arr
  = show (take cutoff l) ++ if length l > cutoff then ".." else ""
  where
    l      = toList arr
    cutoff = 5
showPreExpOp :: PreExp acc exp t -> String
showPreExpOp (Tag i)            = "Tag" ++ show i
showPreExpOp (Const c)          = "Const " ++ show c
showPreExpOp Undef              = "Undef"
showPreExpOp Tuple{}            = "Tuple"
showPreExpOp Prj{}              = "Prj"
showPreExpOp IndexNil           = "IndexNil"
showPreExpOp IndexCons{}        = "IndexCons"
showPreExpOp IndexHead{}        = "IndexHead"
showPreExpOp IndexTail{}        = "IndexTail"
showPreExpOp IndexAny           = "IndexAny"
showPreExpOp ToIndex{}          = "ToIndex"
showPreExpOp FromIndex{}        = "FromIndex"
showPreExpOp Cond{}             = "Cond"
showPreExpOp While{}            = "While"
showPreExpOp PrimConst{}        = "PrimConst"
showPreExpOp PrimApp{}          = "PrimApp"
showPreExpOp Index{}            = "Index"
showPreExpOp LinearIndex{}      = "LinearIndex"
showPreExpOp Shape{}            = "Shape"
showPreExpOp ShapeSize{}        = "ShapeSize"
showPreExpOp Intersect{}        = "Intersect"
showPreExpOp Union{}            = "Union"
showPreExpOp Foreign{}          = "Foreign"
showPreExpOp Coerce{}           = "Coerce"