I have a utility function that lists all the values โโof a type that is both enumerated and limited:
enumerate :: (Enum a, Bounded a) => [a] enumerate = [minBound .. maxBound]
and a data type that includes mapping enumerated types to integers:
data Attribute a = Attribute { test :: a -> Int , vals :: [Int] , name :: String }
Where vals
is a list of integers representing all possible enumerated values. For example, if I had
data Foo = Zero | One | Two deriving (Enum,Bounded)
then vals
will be [0,1,2]
.
I want to be able to create these attributes programmatically, just a given function that maps a
to an enumerated type and name. Something like that:
attribute :: (Enum b, Bounded b) => (a -> b) -> String -> Attribute a attribute f str = Attribute (fromEnum . f) vs str where vs = map fromEnum enumerate
This does not check the type, because there is no way to connect the call with enumerate
with b
in the type signature. So I thought I could do this:
vs = map fromEnum $ enumerate :: [b]
but this also does not compile - the compiler renames b
to b1
. I tried to be smarter using the GADT extension:
attribute :: (Enum b, Bounded b, b ~ c) => {- ... -} vs = map fromEnum $ enumerate :: (Enum c,Bounded c) => [c]
but again c
renamed to c1
.
I donโt want to include type b
as a parameter in the Attribute
type (mainly because I want to store attribute lists with potentially different values โโof b
- thatโs why test
is of type a -> Int
and vals
is of type [Int]
).
How can I write this code to execute what I want?