2012-10-19 9 views
19

Voglio ottenere qualcosa di simile agli array limitati nel pacchetto di array standard ma usando array di repa.Array di Repa indicizzati da un tipo di dati limitato?

Qual è il modo bello e pulito per raggiungere questo obiettivo?

Questo è quello che ho provato, ma ci deve essere un modo migliore di avvolgere tutto in funzioni personalizzate che verificare la presenza di limiti:

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))) 

Inoltre ho cercato di ricavare un'istanza Shape per (sh:. C) ma inutilmente, non riesco davvero a capire come implementare alcune delle interfacce dichiarate nella classe Shape per il mio tipo di dati. Sto scrivendo la domanda con la speranza che qualcun altro abbia un modo, ma se no, ci riproverò. Grazie!

risposta

2

È possibile creare un'istanza di forma per un wrapper attorno all'enumerazione delimitata. Non sono sicuro che questo sia il modo migliore, ma in qualche modo fa quello che vuoi, penso.

{-# LANGUAGE ScopedTypeVariables #-} 

import Data.Array.Repa 

Qui creiamo un'istanza di forma sopra le cose delimitate. Abbiamo bisogno di un end-of-index per gli array "completi".

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 questo, la parte ballottaggio è semplice e pulito:

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] 
+0

farò dare un'occhiata a questo. – user1105045