2012-10-19 3 views
19

Ich möchte etwas Ähnliches wie die begrenzten Arrays im Standard-Array-Paket, aber mit Repa-Arrays erreichen.Repa-Arrays, die durch einen beschränkten Datentyp indiziert sind?

Was ist der schöne und saubere Weg, dies zu erreichen?

Dies ist, was ich versuchte, aber es muss ein besserer Weg, als alles, was in benutzerdefinierten Funktionen Verpackung, die für die Überprüfung von Grenzen:

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

Auch habe ich versucht, eine Shape-Instanz für (sh abzuleiten. C) aber ohne Erfolg kann ich nicht wirklich verstehen, wie einige der Interfaces implementiert werden, die in der Shape-Klasse für meinen Datentyp deklariert sind. Ich schreibe die Frage mit der Hoffnung, dass jemand anders einen Weg hat, aber wenn nicht, werde ich es erneut versuchen. Vielen Dank!

Antwort

2

Sie können eine Shape-Instanz für einen Wrapper um Ihre beschränkte Enum erstellen. Ich bin mir nicht sicher, ob das der beste Weg ist, aber es macht, was du willst, denke ich.

{-# LANGUAGE ScopedTypeVariables #-} 

import Data.Array.Repa 

Hier machen wir eine Shape Instanz über begrenzte Dinge. Wir brauchen ein Ende des Index für "volle" Arrays.

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 

Damit ist die Abstimmung Teil einfach und sauber:

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

ich einen Blick auf diese nehmen. – user1105045

Verwandte Themen