In a recent question of mine I found an answer using a type class of kinds. NB that in HasNProxyK k
, k
is the kind of the second NProxyK
parameter.
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeInType #-}
import GHC.TypeLits hiding ( (*) )
import Data.Kind
class HasNProxyK j where
data NProxyK (n :: Nat) (a::j) :: k
instance HasNProxyK Type where
data NProxyK n a = NProxyK0
instance HasNProxyK k => HasNProxyK (j -> k) where
data NProxyK n f = NProxyKSuc -- or NProxyKS (ProxyK n (f a))
type family ToNProxyK (n :: Nat) (a :: k) :: k where
ToNProxyK n (a :: Type) = NProxyK n a
ToNProxyK n (a :: j -> k) = NProxyK n a
I'm unsatisfied with the above in at least one way. I would have liked to declare the type family with a constraint in its kind, something like:
type family ToNProxyK (n :: Nat) (a :: HasNProxyK k => k) :: k where
ToNProxyK n (a::Type) = Type
ToNProxyK n (a :: j -> k) = NProxyK n a
My intent being that I'm constraining the kind of a
to belong to HasNProxyK
. And in order to use the type family i must know that the class instance is satisfied--hopefully catching declarations like ToNProxyK 3 True
at compilation. However, when I try the above ghc tells me:
src/Traversal.hs:359:15: error:
• Expected kind ‘HasNProxyK k0 => k0’,
but ‘(a :: Type)’ has kind ‘*’
• In the second argument of ‘ToNProxyK’, namely ‘(a :: Type)’
In the type family declaration for ‘ToNProxyK’
|
359 | ToNProxyK n (a :: Type) = NProxyK n a
| ^^^^^^^^^^^
What I get from this is that I'm not actually declaring what I think I'm declaring. That I've specified a new kind, not just restricted the kinds which
are accepted. I've also tried including the constraint in the member types (HasNProxyK Type => Type
) but that just leads to other problems.
So, what am I actually declaring in my constrained kind family? Is there a way to constrain k
in this type family to disallow types such as ToNProxyK n True
?