I defined a custom GADT where the type constructor has a type class constraint on the type variable, like this:
data MyGadt x where
Sample :: Show a => a -> MyGadt a
Now, if I define the following two functions:
foo (Sample a) = show a
bar a = Sample a
GHC infers types for them that are a bit irritating to me.
foo :: MyGadt x -> [Char]
doesn't mention the Show
constraint for x
, while bar :: Show a => a -> MyGadt a
does require the constraint to be mentioned explicitly.
I was assuming that I don't have to mention the constraint because it is declared in the GADT definition.
The only thing I can think of being part of the reason is the position of the GADT in the function. I'm not super deep into that but as far as I understand it, MyGadt
is in positive position in foo
and in negative position in bar
.
When do I have to mention the type class constraints explicitly, and when does GHC figure it out itself based on the constraint on the GADTs type constructor?
Sample :: ShowDict a -> a -> MyGadt a
: you have to pass the extra argument on construction, and you get that value back on pattern matching. Constraints work in exactly the same way. – chibar :: a -> MyGadt a
claims that you can constructMyGadt T
regardless ofT
, even ifT
is not inShow
, but that’s not true becauseSample
requires aShow
instance. Whereasbar :: Show a => a -> MyGadt a
explicitly specifies thatbar @T
requiresT
to be inShow
. – Jon Purdy