Here are some type constructors:
type T0 = Type
type I0 :: T0 -> T0
data I0 x = I0 { getI0 :: x }
type K0 :: T0 -> (T0 -> T0)
data K0 x y = K0 { getK0 :: x }
type Mu0 :: (T0 -> T0) -> T0
data Mu0 f = Mu0 { unMu0 :: f (Mu0 f) }
Here are some more type constructors:
type T1 = Type -> Type
type I1 :: T1 -> T1
data I1 f x = I1 { getI1 :: f x }
type K1 :: T1 -> (T1 -> T1)
data K1 f g x = K1 { getK1 :: f x }
type Mu1 :: (T1 -> T1) -> T1
data Mu1 ff x = Mu1 { unMu1 :: ff (Mu1 ff) x }
We can organize these type constructors into a data family:
class Context (k :: Type)
where
data I :: k -> k
data K :: k -> (k -> k)
data Mu :: (k -> k) -> k
instance Context Type
where
data I x = I0 { getI0 :: x }
data K x y = K0 { getK0 :: x }
data Mu f = Mu0 { getMu0 :: f (Mu0 f) }
instance Context (Type -> Type)
where
data I f x = I1 { getI1 :: f x }
data K f g x = K1 { getK1 :: f x }
data Mu ff x = Mu1 { unMu1 :: ff (Mu1 ff) x }
instance Context (Type -> Type -> Type)
...
instance Context ((Type -> Type) -> Type)
...
These definitions are an example of ad-hoc polymorphism, in that I must laboriously instantiate the class on a case by case basis for each Type-producing kind I can think of. Is it possible to define these datatype constructors in a parametrically polymorphic way, so that we have datatype constructors of kind:
type I :: forall k. k -> k
type K :: forall k. k -> (k -> k)
type Mu :: forall k. (k -> k) -> k
which I can instantiate at any Type producing kind without further ceremony (e.g. instantiating a class for said kind)?