arrays - ¿Repa matrices indexadas por un tipo de datos acotados?
haskell (1)
Puede crear una instancia de forma para un envoltorio alrededor de su enumeración limitada. No estoy seguro de que esta sea la mejor manera, pero creo que hace lo que quieres.
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Array.Repa
Aquí hacemos una instancia de forma sobre cosas limitadas. Necesitamos un final de índice para matrices "completas".
data Idx a = Idx a | EOI
deriving (Eq, Ord, Show)
fromIdx :: forall a . (Bounded a, Enum a) => Idx a -> Int
fromIdx EOI = fromEnum (maxBound :: a) - fromEnum (minBound :: a) + 1
fromIdx (Idx x) = fromEnum x - fromEnum (minBound :: a)
toIdx :: forall a . (Bounded a, Enum a) => Int -> Idx a
toIdx 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) + 1
instance (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
Con eso, la parte de la boleta es fácil y limpia:
data C = A | F | L deriving (Eq, Enum, Ord, Bounded, Show)
data Ballot c = Ballot { vote :: Array U (Idx c) Int
} deriving Show
mkBallot :: (Eq c, Enum c, Ord c, Bounded c, Show c) => c -> Ballot c
mkBallot c = Ballot $ fromListUnboxed EOI vec
where
vec = map (fromEnum . (== c)) [minBound .. maxBound]
Quiero lograr algo similar a las matrices delimitadas en el paquete de matrices estándar pero utilizando matrices de repa.
¿Cuál es la manera agradable y limpia de lograr esto?
Esto es lo que intenté, pero debe haber una mejor manera que envolver todo en funciones personalizadas que verifiquen los límites:
import Data.Array.Repa
data C = A | F | L deriving (Eq,Enum,Ord,Bounded,Show)
data Ballot c = Ballot {
vote::Array U (Z :. Int) Int
} deriving Show
mkBallot::(Eq c ,Enum c,Ord c, Bounded c, Show c) => c -> Ballot c
mkBallot c = Ballot $ fromListUnboxed (Z :. max) (genSc c)
where
max = (fromEnum (maxBound `asTypeOf` c)) + 1
genSc::(Eq c,Enum c,Ord c,Bounded c,Show c) => c -> [Int]
genSc c = [ f x | x <- enumFrom (minBound `asTypeOf` c) , let f v = if x == c then 1 else 0]
showScore c b = index (vote b) (Z :. ((fromEnum c)))
También he intentado derivar una instancia de Shape para (sh:. C) pero, en vano, no puedo entender cómo implementar algunas de las interfaces declaradas en la clase Shape para mi tipo de datos. Estoy escribiendo la pregunta con la esperanza de que alguien más tenga alguna forma, pero si no, lo intentaré de nuevo. ¡Gracias!