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?