我有一个数据类型
newtype Zq q = Zq (IntType q)其中'q‘将是类的一个实例
class Foo a where
type IntType a而'IntType‘仅仅是与'q’相关联的底层表示法(即Int,积分等)。
我想让Zq成为Data.Vector.Unbox的一个实例。我们目前正在使用大约50行普通代码手工派生Unbox,如上面的链接所建议的那样。我们将在代码中创建几个不同类型的“Unbox”,因此为每种类型编写50行并不吸引人。
我找到了两种选择这里。另一种选择是使用这个包裹,它使用模板Haskell派生Unbox的实例。TH代码看起来应该是:
derivingUnbox "Zq"
[d| instance (Foo q, U.Unbox (IntType q)) => Unbox' (ZqBasic q) (IntType q) |]
[| \ (Zq x) -> x |]
[| \ x -> Zq x |]问题是,我可以无法使用关联类型同义词定义实例 (或者我可以吗?)
[一个相关的问题:为什么TypeSynonymInstances ( FlexibleInstances所暗示的一个扩展)不允许关联的类型同义词实例?这是完全不同的野兽吗?]
我目前解决这个问题的方法是将Zq重新定义为
newtype Zq q i = Zq i,然后添加相等约束。
i~(IntType q)在涉及(Zq )的每一个实例中,这都不是很优雅。我的(工作)开箱派生变成
derivingUnbox "Zq"
[d| instance (U.Unbox i, i~IntType q, Foo q) => Unbox' (Zq q i) i |]
[| \ (Zq x) -> x |]
[| \ x -> Zq x |]我觉得我应该能够做到这一点,而不需要显式地暴露类型'i‘。我所做的就是将它从关联类型同义词移到带有等式约束的显式参数。为什么这种“根本上”的方法不同(而且显然更安全)?有什么方法可以避免添加类型参数'i‘而仍然得到自动开箱派生吗?
除了额外的类型参数外,我很难使用TH包来派生Unbox for ( Vectors ),也就是说,我想要生成Unbox的Unbox向量。我的尝试是:
newtype Bar r = Bar (Vector r)
derivingUnbox "Bar"
[d| instance (Unbox r) => Unbox' (Bar r) (Vector r) |]
[| \ (Bar x) -> x |]
[| \ x -> Bar x |]但我会犯(很多)错误,比如:
`basicUnsafeFreeze` is not a (visible) method of class `Data.Vector.Generic.Base.Vector`我不知道为什么它找不到这个方法,因为它对我的Zq类型很好。
列出的第二种方法是使用扩展上图。我看到这种方法最大的问题是,我有一些实际数据(而不是Newtype),我需要打开这些数据。但是,只要使用扩展,我就可以编写
newtype Zq q = Zq (IntType q) deriving (Unbox, M.MVector MVector, G.Vector Vector)或者至少
newtype Zq q i = Zq i deriving (Unbox, M.MVector MVector, G.Vector Vector)第一种导致错误:
No instance for (Unbox (IntType q)) arising from the `deriving` clause of a data type declaration
No instance for (M.MVector MVector (IntType q)) ""
No instance for (G.Vector Vector (IntType q)) ""第二条是:
No instance for (M.MVector MVector i) ""
No instance for (G.Vector U.Vector i) ""我不知道为什么它不能导出这些实例,因为上面的帖子让我相信它应该能够。也许我可以通过使用与GeneralizedNewtypeDeriving相关联的类型同义词来解决问题?(当我需要为‘data’s派生Unbox时,这仍然(可能)不能解决我的问题。)
谢谢你的帮忙!
发布于 2012-07-10 22:10:44
您在这里遇到了几个单独的问题:
TH方法
是的,关联类型同义词的类实例是非法的。
确实,您不能为关联的类型同义词或类型函数定义类实例,这是有充分理由的:编译器无法判断它们是否重叠。例如:
type family F a
instance Eq (F Int)
instance Eq (F Bool)这些实例是否重叠?考虑到上面的源代码,我们无法判断:这取决于以后某个人如何定义F的实例。例如,他们可以定义
type instance F Int = Double
type instance F Bool = Double然后,Eq的两个实例实际上是重叠的。
您遇到了vector-th-unbox包的问题
如果查看所需的实际Unbox实例,实际上并不需要IntType q的实例;您想要的只是以下内容:
instance (Unbox (IntType q), Foo q) => Unbox (Zq q) where
...问题是,vector-th-unbox包迫使您使用假类型类Unbox'来通信中间表示类型(在您的示例中是IntType q),这是滥用模板Haskell的语法传递类型的一种方便方法。然后,GHC看到您已经编写了Unbox' (Zq q) (IntType q)和抱怨。我建议为vector-th-unbox包提交一个bug。
Unbox for Vector r
我想路易斯·沃瑟曼报道过这件事。
GeneralizedNewtypeDeriving方法
您所遇到的具体编译错误是因为GHC无法推断适当的上下文。对于大多数与您所遇到的问题类似的问题,StandaloneDeriving语言扩展将解决您的问题:
deriving instance Unbox (IntType q) => Unbox (Zq q)
deriving instance Unbox (IntType q) => M.MVector MVector (Zq q)
deriving instance Unbox (IntType q) => G.Vector Vector (Zq q)但别这么做!
虽然GeneralizedNewtypeDeriving经常做您想做的事情,但是它在几种基本途径中是坏的,它生成的Unbox实例是完全破碎!所以,在游说李阳解决你当前的问题后,坚持第四种方法。
发布于 2012-11-18 06:35:38
https://stackoverflow.com/questions/11399143
复制相似问题