Repa arrays indexed by a bounded data type?
You can make a shape instance for a wrapper around your bounded enum. I'm not sure this is the best way, but it sort of does what you want, I think.
{-# LANGUAGE ScopedTypeVariables #-}import Data.Array.Repa
Here we make a shape instance over bounded things. We need an end-of-index for "full" arrays.
data Idx a = Idx a | EOI deriving (Eq, Ord, Show)fromIdx :: forall a . (Bounded a, Enum a) => Idx a -> IntfromIdx EOI = fromEnum (maxBound :: a) - fromEnum (minBound :: a) + 1fromIdx (Idx x) = fromEnum x - fromEnum (minBound :: a)toIdx :: forall a . (Bounded a, Enum a) => Int -> Idx atoIdx i | i < 0 = error "negative index"toIdx i = case compare i range of LT -> Idx $ toEnum (i + fromEnum (minBound :: a)) EQ -> EOI GT -> error "out of range" where range = fromEnum (maxBound :: a) - fromEnum (minBound :: a) + 1instance (Bounded a, Enum a, Ord a) => Shape (Idx a) where rank _ = 1 zeroDim = Idx minBound unitDim = Idx $ succ minBound intersectDim EOI n = n intersectDim n EOI = n intersectDim (Idx n1) (Idx n2) = Idx $ min n1 n2 addDim = error "undefined" size = fromIdx sizeIsValid _ = True toIndex _ n = fromIdx n fromIndex _ i = toIdx i inShapeRange _ _ EOI = error "bad index" inShapeRange n1 n2 n = n >= n1 && n <= n2 listOfShape n = [fromIdx n] shapeOfList [i] = toIdx i shapeOfList _ = error "unsupported shape" deepSeq (Idx n) x = n `seq` x deepSeq _ x = x
With that, the ballot part is easy and clean:
data C = A | F | L deriving (Eq, Enum, Ord, Bounded, Show)data Ballot c = Ballot { vote :: Array U (Idx c) Int } deriving ShowmkBallot :: (Eq c, Enum c, Ord c, Bounded c, Show c) => c -> Ballot cmkBallot c = Ballot $ fromListUnboxed EOI vec where vec = map (fromEnum . (== c)) [minBound .. maxBound]