鉴于我有数据类型
data A a = A a
data B b = B b
和类型类
class C c where
f :: c a -> a
现在C类需要一种类型* -> *
,所以我可以做
instance C A where
f (A a) = a
instance C B where
f (B b) = b
现在给出一个如下函数:
ab :: b -> A (B b)
ab = A . B
如何为结果类型声明C
的实例?
我首先通过我可以使用TypeSynonymInstances
的类型同义词,如下所示:
type AB b = A (B b)
class C AB where
f (A (B b)) = b
特别是因为ghci报告了正确的类型:
*Main> :k AB
AB :: * -> *
但是,您似乎无法在实例声明中使用部分应用的类型同义词(或者在任何地方使用)。
我是否可以通过某种方式组合类型A
和B
,就像我可以编写构造函数一样,或者使用其他语法来声明这种嵌套类型的实例?
答案 0 :(得分:6)
最简单的可能是定义
newtype AB a = AB { unAB :: A (B a) }
GHC应该能够为此派生一个C实例。
您也可以使用TypeCompose来完成此操作,
type AB = A :. B
instance C AB where
f = f . f . unO
答案 1 :(得分:2)
无法声明此类实例。实际上,在实例声明中允许任意类型的函数(如AB
)会使实例解析不可判定。
通常,解决方案是声明一个newtype。当然,当您想要使用该类时,您必须显式转换为newtype。
newtype AB a = AB (A (B a))
instance C AB where f (AB (A (B a)) = a
如果您对该类的使用足够简单,您可能只想将重载方法作为使用它的函数的参数传递。
答案 2 :(得分:1)
您必须使用newtype
。必须始终完全应用类型同义词,因为它只是同义词,而不是lambda。 newtype
没有运行时惩罚;它将在编译时被删除。