Подтвердить что ты не робот

Массивы Repa, индексированные ограниченным типом данных?

Я хочу добиться чего-то похожего на ограниченные массивы в пакете стандартных массивов, но используя репа-массивы.

Какой хороший и чистый способ достичь этого?

Это то, что я пробовал, но должен быть лучший способ, чем обернуть все в пользовательских функциях, которые проверяют границы:

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

Также я попытался получить экземпляр Shape для (sh:. C), но безрезультатно, я не могу понять, как реализовать некоторые из интерфейсов, объявленных в классе Shape для моего типа данных, Я пишу вопрос с надеждой, что у кого-то есть способ, но если нет, я попробую еще раз. Спасибо!

4b9b3361

Ответ 1

Вы можете создать экземпляр формы для обертки вокруг вашего ограниченного перечисления. Я не уверен, что это лучший способ, но я думаю, что это похоже на то, что вы хотите.

{-# LANGUAGE ScopedTypeVariables  #-}

import Data.Array.Repa

Здесь мы создаем экземпляр формы над ограниченными вещами. Нам нужен конец индекса для "полных" массивов.

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

При этом часть бюллетеня проста и чиста:

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]