我有一个数据类型
newtype Zq q = Zq (IntType q)
其中'q'将是该类的实例
class Foo a where
type IntType a
和'IntType'只是与'q'相关的基础表示(即Int,Integral等)。
我想让Zq成为Data.Vector.Unbox的一个实例。我们目前正在使用大约50行简单代码手动派生Unbox,如上面的链接所示。我们将在代码中创建几种不同类型的“Unbox”,因此为每种类型写入50行并不吸引人。
我找到了两个替代here。一种替代方法是使用this package,它使用Template Haskell来派生Unbox的实例。 TH代码看起来像:
derivingUnbox "Zq"
[d| instance (Foo q, U.Unbox (IntType q)) => Unbox' (ZqBasic q) (IntType q) |]
[| \ (Zq x) -> x |]
[| \ x -> Zq x |]
问题是,我can't define instances using associated type synonyms(或者我可以??)
[相关问题:为什么TypeSynonymInstances是FlexibleInstances所暗示的扩展,不允许关联的类型同义词实例?这在某种程度上是一个根本上不同的野兽吗?]
我目前解决该问题的方法是将Zq重新定义为
newtype Zq q i = Zq i
然后添加等式约束
i~(IntType q)
在涉及(Zq q i)的每个实例中,这都不是很优雅。我的(工作)Unbox派生变为
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'并仍然获得自动Unbox派生?
除了额外的类型参数,我在使用TH包导出Unbox for(Vector r)时遇到了麻烦,也就是说,我想制作Unbox Vector的Unbox Vector。我的尝试是这样的:
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类型时。
列出的第二种方法above正在使用扩展名GeneralizedNewtypeDeriving。我用这种方法看到的最大问题是我有一些实际的数据(而不是Newtype),我需要成为Unbox。但是,只使用扩展名,我应该可以写
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相关联的类型同义词来逃避? (当我需要为'数据'派生Unbox时,这仍然(可能)无法解决我的问题。)
感谢您的帮助!
答案 0 :(得分:4)
我已经更改了4820b73中的语法,所以你应该能够做你想做的事情:
derivingUnbox "Complex"
[d| (Unbox a) ⇒ Complex a → (a, a) |]
[| \ (r :+ i) → (r, i) |]
[| \ (r, i) → r :+ i |]
我还修复了fe37976中的“xyz不是(可见)方法...”错误,尽管可以使用以下方法解决:
import qualified Data.Vector.Generic
import qualified Data.Vector.Generic.Mutable
现在Hackage。 CC:@reinerp
答案 1 :(得分:3)
你在这里遇到了一些不同的问题:
确实无法为关联的类型同义词或类型函数定义类实例,这是有充分理由的:编译器无法判断它们是否重叠。例如:
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
),作为一种方便的方式滥用Template Haskell的语法来传递一个类型。然后GHC看到你写了Unbox' (Zq q) (IntType q)
并抱怨。我建议为vector-th-unbox
包提交一个错误。
Unbox
Vector r
我认为Louis Wasserman涵盖了这一点。
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
经常完全符合您的要求,但它会在some fundamental ways中被破坏,而它产生的Unbox
实例是completely broken!因此,在游说溧阳解决当前问题后,坚持使用TH方法。