    module Data.Array.Parallel.PArray (
      PArray, Elt, Random(..),

      length, empty, replicate, singleton,
      zip, unzip, enumFromTo, fromList, nf
    ) where

    import Data.Array.Parallel.Lifted.PArray
    import Data.Array.Parallel.Lifted.Instances
    import Data.Array.Parallel.Lifted.Combinators
    import Data.Array.Parallel.Lifted.Prim
    import qualified Data.Array.Parallel.Unlifted as U

    import Data.Array.Parallel.Base ( showsApp )

    import qualified System.Random as R

    import Prelude hiding ( length, replicate, zip, unzip, enumFromTo )

    class Elt a where
      pa :: PA a

    instance Elt Int where
      pa = dPA_Int

    instance Elt Double where
      pa = dPA_Double

    instance (Elt a, Elt b) => Elt (a,b) where
      pa = dPA_2 pa pa

    instance (Elt a, Elt b, Elt c) => Elt (a,b,c) where
      pa = dPA_3 pa pa pa

    instance (Elt a, Elt b, Elt c, Elt d) => Elt (a,b,c,d) where
      pa = dPA_4 pa pa pa pa

    instance (Elt a, Elt b, Elt c, Elt d, Elt e) => Elt (a,b,c,d,e) where
      pa = dPA_5 pa pa pa pa pa

    length :: Elt a => PArray a -> Int
    {-# INLINE length #-}
    length = lengthPA_v pa

    empty :: Elt a => PArray a
    {-# INLINE empty #-}
    empty = emptyPA pa

    replicate :: Elt a => Int -> a -> PArray a
    {-# INLINE replicate #-}
    replicate = replicatePA_v pa

    singleton :: Elt a => a -> PArray a
    {-# INLINE singleton #-}
    singleton = singletonPA_v pa

    zip :: (Elt a, Elt b) => PArray a -> PArray b -> PArray (a,b)
    {-# INLINE zip #-}
    zip = zipPA_v pa pa

    unzip :: (Elt a, Elt b) => PArray (a,b) -> (PArray a, PArray b)
    {-# INLINE unzip #-}
    unzip = unzipPA_v pa pa

    enumFromTo :: Int -> Int -> PArray Int
    {-# INLINE enumFromTo #-}
    enumFromTo = enumFromToPA_v

    fromList :: Elt a => [a] -> PArray a
    {-# INLINE fromList #-}
    fromList = fromListPA pa

    toList :: Elt a => PArray a -> [a]
    toList xs = [indexPA_v pa xs i | i <- [0 .. length xs - 1]]

    nf :: Elt a => PArray a -> ()
    nf = nfPA pa

    instance (Elt a, Show a) => Show (PArray a) where
      showsPrec n xs = showsApp n "fromList<PArray>" (toList xs)

    class Random a where
      randoms  :: R.RandomGen g => Int -> g -> PArray a
      randomRs :: R.RandomGen g => Int -> (a, a) -> g -> PArray a

    prim_randoms :: (PrimPA a, R.Random a, R.RandomGen g) => Int -> g -> PArray a
    prim_randoms n = fromUArrPA' . U.randoms n

    prim_randomRs :: (PrimPA a, R.Random a, R.RandomGen g) => Int -> (a, a) -> g -> PArray a
    prim_randomRs n r = fromUArrPA' . U.randomRs n r

    instance Random Int where
      randoms = prim_randoms
      randomRs = prim_randomRs

    instance Random Double where
      randoms = prim_randoms
      randomRs = prim_randomRs