如何限制类型家族中的种类

时间:2019-05-20 14:55:42

标签: haskell

在我最近的一个问题中,我发现了一个使用种类类型类型的answer。请注意,在HasNProxyK k中,k是第二个NProxyK参数的类型。

{-# 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

我至少以一种方式对上述内容不满意。我想用constraint in its kind声明类型族,例如:

type family ToNProxyK (n :: Nat) (a :: HasNProxyK k => k) :: k where
   ToNProxyK n (a::Type) = Type
   ToNProxyK n (a :: j -> k) = NProxyK n a

我的目的是限制a属于HasNProxyK的种类。而且,为了使用类型族,我必须知道该类实例已满足-希望在编译时捕获诸如ToNProxyK 3 True之类的声明。但是,当我尝试上面的ghc告诉我:

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
    |               ^^^^^^^^^^^

我从中得到的是,我实际上并没有在声明我认为在声明的内容。我指定了一种新的种类,而不仅限于 被接受。我也尝试过在成员类型(HasNProxyK Type => Type)中加入约束,但这只会导致其他问题。

那么,我在这个被束缚的善良家庭中实际上在说什么?是否有一种方法可以限制此类型族中的k禁止使用诸如ToNProxyK n True之类的类型?

1 个答案:

答案 0 :(得分:2)

据我所知,我找不到理想的方法来实现受限的封闭类型族。

但是,对于您的特定情况,使用在类型类中声明的类型族可能就足够了,它可以根据需要约束k

class HasNProxyK k => C k (n :: Nat) (a :: k) where
    type ToNProxyK k n a :: k

instance C Type n a where
    type ToNProxyK Type n a = NProxyK n a

instance HasNProxyK k => C (j -> k) n a where
    type ToNProxyK (j -> k) n a = NProxyK n a

这样做,我们将失去对 closed 类型族的“自顶向下”处理。就您而言,Typej -> k之间没有重叠,因此这不成问题。


简单的变体:

class HasNProxyK k => C k where
    type ToNProxyK k (n :: Nat) (a :: k) :: k

instance C Type where
    type ToNProxyK Type n a = NProxyK n a

instance HasNProxyK k => C (j -> k) where
    type ToNProxyK (j -> k) n a = NProxyK n a