The first variation I tried I feel is the most semantically accurate, as it is clear from the beginning of what I am trying to do. The main "insight" I used was using/assuming extensionality of kinds (and partial application of type synonyms) to define
a kind pair:
type KindPair (a :: ka) (b :: kb) (f :: ka -> kb -> *) = f a b
A pair of kinds is simply anything that "owes the two kinds to the type checker". Thus, if given anything expecting those two kinds, it would feed them to it. This by itself compiles fine. But then when trying to define currying and uncurrying, it won't type
check:
type KCurry (tf :: (KindPair ka kb) -> kc) (ta :: ka) (tb :: kb) = kc
type KUncurry (tf :: ka -> kb -> kc) (tp :: (KindPair ka kb)) = kc
The error I get is: The type synonym ‘KindPair’ should have 3 arguments, but has been given 2
Partial application of type synonyms is fine, I use it all the time. But it seems it is not fine when it is "kind synonyms"??? It is not even asking me for any extension to allow it.
So I tried a more syntactic approach, abusing the notion that GHC treats kinds and types very similarly:
type KindPair (a :: ka) (b :: kb) = ((ka -> kb -> *) -> *)
type KCurry (tf :: (KindPair ka kb) -> kc) = ka -> kb -> kc
type KUncurry (tf :: ka -> kb -> kc) = (KindPair ka kb) -> kc
This type checks, but it is just a mirage. If you check the kinds of KCurry and KUncurry it does not look good:
(KindPair ka kb -> kc) -> *
Uhh... that's not what I said. It's taking the right hand side entirely as a type, not as a kind.
This becomes obvious when we try to use them: