Invisible kinds of GADT can be also generalized
GADT allows you to declare a type whose type parameters are more generic than type of each constructor.
data X a where
XInt :: X Int
As you can see, a is generalized even though you can only create X Int using XInt.
This applies to kinds as well even when they’re invisible. Let’s take an example.
data Y f where
YMaybe :: (a -> Maybe a) -> Y Maybe
GHC infers a kind of Y as (Type -> Type) -> Type. But you can make it more generic by giving it a kind signature.
type Y :: (k -> Type) -> Type
data Y f where
YMaybe :: (a -> Maybe a) -> Y Maybe
Now a kind of f is k -> Type instead of Type -> Type. This first looks weird because there is only one data constructor YMaybe which returns Y Maybe whose kind is Type -> Type.
But just like we could make a of X generalized, we can make a kind of f generalized.
When you have type T indexed by kind S,
type data S = S1 | S2
type T :: S -> Type
data T s = T
you can add a new data constructor to Y where a kind of f is S -> Type.
type Y :: (k -> Type) -> Type
data Y f where
YMaybe :: (a -> Maybe a) -> Y Maybe
YT :: T s -> Y T