I study the functions of the Haskell type family and compute the level level. It seems pretty easy to get level-level parametric polymorphism with PolyKinds
:
{-
I can do things like :kind! Bool == Bool
:kind! Bool == Bool
or :kind! Int == Int
:kind! Int == Int
or :kind! Z == Z
:kind! Z == Z
and :kind! (IZ (SZ)) == (I (SZ) (S (SZ)))
:kind! (IZ (SZ)) == (I (SZ) (S (SZ)))
.
However, I want to make type +
ad-hoc polymorphic. So this is limited to the cases that I give them. The 2 examples here are NatK
view NatK
and IntK
view IntK
.
At first I tried to make it parametrically polymorphic:
infix 6 :+ type family (x :: k) :+ (y :: k) :: k where Z :+ y = y (S x) :+ y = S (x :+ y) (I x1 x2) :+ (I y1 y2) = I (x1 :+ y1) (x2 :+ y2)
It works, how can I do :kind! (I (SZ) Z) :+ (I (SZ) Z)
:kind! (I (SZ) Z) :+ (I (SZ) Z)
.
However, I can also do :kind! Bool :+ Bool
:kind! Bool :+ Bool
. And this makes no sense, but allows you to use it as a simple type constructor. I want to create a type family that does not allow such erroneous types.
At that moment I was lost. I tried class types with the type
parameter. But that did not work.
class NumK (a :: k) (b :: k) where type Add ab :: k instance NumK (Z :: NatK) (b :: NatK) where type Add Z b = b instance NumK (S a :: NatK) (b :: NatK) where type Add (S a) b = S (Add ab) instance NumK (I a1 a2 :: IntK) (I b1 b2 :: IntK) where type Add (I a1 a2) (I b1 b2) = I (Add a1 b1) (Add a2 b2)
It still allows :kind! Add Bool Bool
:kind! Add Bool Bool
.
Is this ConstraintKinds
extension, where do I need to limit :+
or Add
some “cool class”?
source share