使用RankNTypes和TypeFamilies的非法多态或限定类型

时间:2012-12-12 18:31:38

标签: haskell type-families

我一直在慢慢地将llvm包移植到使用数据类型,类型族和type-nats,并在尝试删除用于分类值的两个新类型时遇到了一个小问题({{1通过引入由其constness参数化的新ConstValue类型来引入它。{/ p>

Value仅接受Value个参数,并提供将CallArgs转换为Value 'Variable a的功能。我想概括Value 'Const a以允许每个参数为Value 'Variable aCallArgs。是否可以使用类型系列以某种方式对此进行编码?我认为这可能与fundeps有关。

'Const

......无法编译:

/tmp/blah.hs:10:1:
    Illegal polymorphic or qualified type:
      forall (c :: Const). Value c a
    In the type instance declaration for `CallArgs'

以下解决方案有效(相当于遗留代码),但要求用户强制转换每个常量'Variable

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}

data Const = Const | Variable

data Value (c :: Const) (a :: *)

type family CallArgs a :: * 
type instance CallArgs (a -> b) = forall (c :: Const) . Value c a -> CallArgs b
type instance CallArgs (IO a)   = IO (Value 'Variable a)

2 个答案:

答案 0 :(得分:6)

您要求的CallArgs有点像非确定性函数,需要a -> b并返回Value 'Const a -> blahValue 'Variable a -> blah。有时你可以用非确定性函数来翻转它们;实际上,这个具有确定性的反转。

type family   UnCallArgs a
type instance UnCallArgs (Value c a -> b) = a -> UnCallArgs b
type instance UnCallArgs (IO 'Variable a) = IO a

现在,您可以编写类似

的类型
foo :: CallArgs t -> LLVM t

或类似的东西,你可以写这个:

foo :: t -> LLVM (UnCallArgs t)

当然,您可能希望选择一个比UnCallArgs更好的名称,可能是Native或类似的名称,但这样做很好,需要一些我没有的领域知识。< / p>

答案 1 :(得分:3)

包裹forall c。在newtype AV为你工作?

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}

data CV = Const | Variable

data Value (c :: CV) (a :: *)

data AV a = AV (forall c. Value c a)

type family CallArgs a :: * 
type instance CallArgs (a -> b) = AV a -> CallArgs b
type instance CallArgs (IO a)   = IO (Value 'Variable a)