comfort-array-0.5.5: src/Data/Array/Comfort/Container.hs
{-# LANGUAGE TypeFamilies #-}
{- |
This module provides an array shape type,
that allows to store elements from a container
while preserving the container structure.
-}
module Data.Array.Comfort.Container (
C(..), EqShape(..), NFShape(..), Indexed(..),
) where
import qualified Data.Array.Comfort.Shape as Shape
import Control.DeepSeq (NFData, rnf)
import qualified Data.NonEmpty.Map as NonEmptyMap
import qualified Data.NonEmpty.Set as NonEmptySet
import qualified Data.NonEmpty.Class as NonEmptyC
import qualified Data.NonEmpty as NonEmpty
import qualified Data.Empty as Empty
import qualified Data.Map as Map
import qualified Data.Set as Set
-- import qualified Data.Complex as Complex
import Data.Map (Map)
import Data.Set (Set)
import Data.Foldable (Foldable)
import Data.Maybe (fromMaybe)
-- import Data.Complex (Complex((:+)))
class (Foldable f) => C f where
data Shape f
shapeSize :: Shape f -> Int
fromList :: Shape f -> [a] -> f a
toShape :: f a -> Shape f
class (C f) => NFShape f where
rnfShape :: Shape f -> ()
class (C f) => EqShape f where
eqShape :: Shape f -> Shape f -> Bool
class (C f) => Indexed f where
type Index f
indices :: Shape f -> [Index f]
unifiedSizeOffset ::
(Shape.Checking check) =>
Shape f -> (Int, Index f -> Shape.Result check Int)
instance (NFShape f) => NFData (Shape f) where
rnf = rnfShape
instance (EqShape f) => Eq (Shape f) where
(==) = eqShape
instance (C f) => Shape.C (Shape f) where
size = shapeSize
instance (Indexed f) => Shape.Indexed (Shape f) where
type Index (Shape f) = Index f
indices = indices
unifiedSizeOffset = unifiedSizeOffset
instance C [] where
data Shape [] = ShapeList Int
deriving (Show)
shapeSize (ShapeList n) = n
toShape = ShapeList . length
fromList _ = id
instance EqShape [] where
eqShape (ShapeList n) (ShapeList m) = n==m
instance NFShape [] where
rnfShape (ShapeList n) = rnf n
instance Indexed [] where
type Index [] = Int
indices (ShapeList len) = take len $ iterate (1+) 0
unifiedSizeOffset (ShapeList len) =
(len, \ix -> do
Shape.assert "Shape.Container.[]: array index too small" $ ix>=0
Shape.assert "Shape.Container.[]: array index too big" $ ix<len
return ix)
{-
instance Foldable only available since GHC-8.0. :-(
Could be circumvented by Data.Orphans
but that one also pulls in lots of dangerous instances.
instance C Complex where
data Shape Complex = ShapeComplex
shapeSize ShapeComplex = 2
toShape (_:+_) = ShapeComplex
fromList ShapeComplex xs =
case xs of
[r,i] -> r Complex.:+ i
_ -> error "ShapeComplex: not two elements"
instance EqShape Complex where
eqShape ShapeComplex ShapeComplex = True
instance NFShape Complex where
rnfShape ShapeComplex = ()
-}
instance (C f) => C (NonEmpty.T f) where
data Shape (NonEmpty.T f) = ShapeNonEmpty (Shape f)
shapeSize (ShapeNonEmpty c) = 1 + shapeSize c
toShape = ShapeNonEmpty . toShape . NonEmpty.tail
fromList (ShapeNonEmpty c) xt =
case xt of
[] -> error "ShapeNonEmpty: empty list"
x:xs -> NonEmpty.cons x $ fromList c xs
instance (EqShape f) => EqShape (NonEmpty.T f) where
eqShape (ShapeNonEmpty a) (ShapeNonEmpty b) = a==b
instance (NFShape f) => NFShape (NonEmpty.T f) where
rnfShape (ShapeNonEmpty c) = rnfShape c
instance (C f) => Indexed (NonEmpty.T f) where
type Index (NonEmpty.T f) = Int
indices shape = take (shapeSize shape) $ iterate (1+) 0
unifiedSizeOffset shape =
let len = shapeSize shape in
(len, \ix -> do
Shape.assert "Shape.Container.NonEmpty: array index too small" $ ix>=0
Shape.assert "Shape.Container.NonEmpty: array index too big" $ ix<len
return ix)
instance C Empty.T where
data Shape Empty.T = ShapeEmpty
deriving (Show)
shapeSize ShapeEmpty = 0
toShape Empty.Cons = ShapeEmpty
fromList ShapeEmpty xs =
case xs of
[] -> Empty.Cons
_ -> error "ShapeEmpty: not empty"
instance EqShape Empty.T where
eqShape ShapeEmpty ShapeEmpty = True
instance NFShape Empty.T where
rnfShape ShapeEmpty = ()
instance (Ord k) => C (Map k) where
data Shape (Map k) = ShapeMap (Set k)
deriving (Show)
shapeSize (ShapeMap set) = Set.size set
toShape = ShapeMap . Map.keysSet
fromList (ShapeMap set) = Map.fromAscList . zip (Set.toAscList set)
instance (Ord k) => EqShape (Map k) where
eqShape (ShapeMap set0) (ShapeMap set1) = set0==set1
instance (NFData k, Ord k) => NFShape (Map k) where
rnfShape (ShapeMap set) = rnf set
instance (Ord k) => Indexed (Map k) where
type Index (Map k) = k
indices (ShapeMap set) = Set.toAscList set
unifiedSizeOffset (ShapeMap set) = Shape.unifiedSizeOffset set
instance (Ord k) => C (NonEmptyMap.T k) where
data Shape (NonEmptyMap.T k) = ShapeNonEmptyMap (NonEmptySet.T k)
deriving (Show)
shapeSize (ShapeNonEmptyMap set) = NonEmptySet.size set
toShape = ShapeNonEmptyMap . NonEmptyMap.keysSet
fromList (ShapeNonEmptyMap set) =
NonEmptyMap.fromAscList . NonEmptyC.zip (NonEmptySet.toAscList set) .
fromMaybe (error "ShapeNonEmptyMap: empty list") . NonEmpty.fetch
instance (Ord k) => EqShape (NonEmptyMap.T k) where
eqShape (ShapeNonEmptyMap set0) (ShapeNonEmptyMap set1) = set0==set1
instance (NFData k, Ord k) => NFShape (NonEmptyMap.T k) where
rnfShape (ShapeNonEmptyMap set) = rnf set
instance (Ord k) => Indexed (NonEmptyMap.T k) where
type Index (NonEmptyMap.T k) = k
indices (ShapeNonEmptyMap set) =
NonEmpty.flatten $ NonEmptySet.toAscList set
unifiedSizeOffset (ShapeNonEmptyMap set) =
Shape.unifiedSizeOffset (NonEmptySet.flatten set)