Skip to the content.

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