我一直在慢慢地将llvm包移植到使用数据类型,类型族和type-nats,并在尝试删除用于分类值的两个新类型时遇到了一个小问题({{1通过引入由其constness参数化的新ConstValue
类型来引入它。{/ p>
Value
仅接受Value
个参数,并提供将CallArgs
转换为Value 'Variable a
的功能。我想概括Value 'Const a
以允许每个参数为Value 'Variable a
或CallArgs
。是否可以使用类型系列以某种方式对此进行编码?我认为这可能与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)
答案 0 :(得分:6)
您要求的CallArgs
有点像非确定性函数,需要a -> b
并返回Value 'Const a -> blah
或Value '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)