    {-# LANGUAGE RankNTypes #-}

    -- | Class of types that can be used as array shapes and indices.
    module Data.Array.Repa.Shape
    	( Shape(..)
            , inShape
            , showShape )
    where

    -- Shape ----------------------------------------------------------------------
    -- | Class of types that can be used as array shapes and indices.
    class Eq sh => Shape sh where

    	-- | Get the number of dimensions in a shape.
    	rank	:: sh -> Int

    	-- | The shape of an array of size zero, with a particular dimensionality.
    	zeroDim	:: sh

    	-- | The shape of an array with size one, with a particular dimensionality.
    	unitDim :: sh

    	-- | Compute the intersection of two shapes.
    	intersectDim :: sh -> sh -> sh

    	-- | Add the coordinates of two shapes componentwise
    	addDim  :: sh -> sh -> sh

    	-- | Get the total number of elements in an array with this shape.
    	size	:: sh -> Int

    	-- | Check whether this shape is small enough so that its flat
    	--	indices an be represented as `Int`. If this returns `False` then your
    	--	array is too big. Mostly used for writing QuickCheck tests.
    	sizeIsValid :: sh -> Bool

    	-- | Convert an index into its equivalent flat, linear, row-major version.
    	toIndex :: sh	-- ^ Shape of the array.
    		-> sh 	-- ^ Index into the array.
    		-> Int

    	-- | Inverse of `toIndex`.
    	fromIndex
    		:: sh 	-- ^ Shape of the array.
    		-> Int 	-- ^ Index into linear representation.
    		-> sh

    	-- | Check whether an index is within a given shape.
    	inShapeRange
    		:: sh 	-- ^ Start index for range.
    		-> sh 	-- ^ Final index for range.
    		-> sh 	-- ^ Index to check for.
    		-> Bool

    	-- | Convert a shape into its list of dimensions.
    	listOfShape	:: sh -> [Int]

    	-- | Convert a list of dimensions to a shape
    	shapeOfList	:: [Int] -> sh

    	-- | Ensure that a shape is completely evaluated.
    	infixr 0 `deepSeq`
    	deepSeq :: sh -> a -> a

    -- | Check whether an index is a part of a given shape.
    inShape :: forall sh
    	.  Shape sh
    	=> sh 		-- ^ Shape of the array.
    	-> sh		-- ^ Index.
    	-> Bool

    {-# INLINE inShape #-}
    inShape sh ix
    	= inShapeRange zeroDim sh ix

    -- | Nicely format a shape as a string
    showShape :: Shape sh => sh -> String
    showShape = foldr (\sh str -> str ++ " :. " ++ show sh) "Z" . listOfShape