Given a typeclass definition like the following, I'd like to enumerate the MyClassId a
type for any type that is an instance of MyClass
.
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
class
( Enum (MyClassId e)
, Bounded (MyClassId e))
=> MyClass e where
type MyClassId e :: *
enumMyClassId :: MyClass a => [MyClassId a]
enumMyClassId = enumFrom minBound
However, when I try to compile this snippet of code, GHC 7.10.2 complains with the following message:
enumTypeClass.hs:12:18: Couldn't match type ‘MyClassId a0’ with ‘MyClassId a’ NB: ‘MyClassId’ is a type function, and may not be injective The type variable ‘a0’ is ambiguous Expected type: [MyClassId a] Actual type: [MyClassId a0] In the ambiguity check for the type signature for ‘enumMyClassId’: enumMyClassId :: forall a. MyClass a => [MyClassId a] To defer the ambiguity check to use sites, enable AllowAmbiguousTypes In the type signature for ‘enumMyClassId’: enumMyClassId :: MyClass a => [MyClassId a]
I am not exactly sure why it can't infer that the a
type variable is the same as the a
in the constraint for the function enumMyClassId
. One possible fix is to change the function enumMyClassId
to the following:
enumMyClassId :: MyClass a => a -> [MyClassId a]
enumMyClassId _ = enumFrom minBound
But this is not very elegant as it introduces an unused variable just to make the program typecheck. Is there some solution that doesn't involve the trick above?
universe :: Universe a => [a]
as a canonical way to enumerate a given type. It has many instances that are not covered by the(Enum a, Bounded a)
constraint -- and skips a few instances that would be covered by that, but in the wrong way, likeDouble
. – Daniel Wagner