Создание списка целых чисел, связанных с типом Enum

У меня есть служебная функция, которая перечисляет все значения перечислимого и ограниченного типа :

enumerate :: (Enum a, Bounded a) => [a]
enumerate = [minBound.. maxBound]

. и тип данных, который включает отображение перечислимых типов в целые числа :

data Attribute a = Attribute { test :: a -> Int
                            , vals :: [Int]
                            , name :: String }

. Где vals— список целых чисел, представляющих все возможные перечисляемые значения. Например, если бы у меня было

data Foo = Zero | One | Two deriving (Enum,Bounded)

тогда valsбудет [0,1,2].

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

attribute :: (Enum b, Bounded b) => (a -> b) -> String -> Attribute a
attribute f str = Attribute (fromEnum. f) vs str
  where
    vs = map fromEnum enumerate

Это не проверка типов, потому что нет способа связать вызов enumerateс bв сигнатуре типа. Так что я подумал, что смогу это сделать:

vs = map fromEnum $ enumerate :: [b]

но это тоже не компилируется -компилятор переименовывает это bв b1. Я пытался быть умнее, используя расширение GADTs:

attribute :: (Enum b, Bounded b, b ~ c) => {-... -}
vs = map fromEnum $ enumerate :: (Enum c,Bounded c) => [c]

но снова cпереименовывается в c1.

Я не хочу включать тип bв качестве параметра в тип Attribute(, главным образом потому, что хочу хранить списки атрибутов с потенциально разными значениями b-. вот почему testимеет тип a -> Int, а valsимеет тип [Int])..

Как я могу написать этот код, чтобы он делал то, что я хочу?

6
задан Chris Taylor 29 July 2012 в 15:20
поделиться