我有一个数据类型
newtype Zq q = Zq (IntType q)
其中 'q' 将是该类的一个实例
class Foo a where
type IntType a
而“IntType”只是与“q”相关的底层表示(即 Int、Integral 等)。
我想让 Zq 成为Data.Vector.Unbox的一个实例。我们目前正在使用上面链接中建议的大约 50 行简单代码手动派生 Unbox。我们将在我们的代码中创建几种不同类型的“拆箱”,因此为每种类型编写 50 行并不吸引人。
我在这里找到了两种选择。一种替代方法是使用这个包,它使用 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 |]
问题是,我无法使用关联的类型同义词定义实例(或者我可以吗??)
[一个相关问题:为什么TypeSynonymInstances是 FlexibleInstances隐含的扩展,不允许关联类型同义词实例?这是某种根本不同的野兽吗?]
我目前对该问题的解决方案是将 Zq 重新定义为
newtype Zq q i = Zq i
然后添加等式约束
i~(IntType q)
在每个涉及 (Zq qi) 的情况下,这不是很优雅。我的(工作)拆箱派生变为
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 包为 (Vector r) 派生 Unbox 时遇到了问题,也就是说,我想制作一个 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 类型时。
上面列出的第二种方法是使用扩展 GeneralizedNewtypeDeriving。我看到这种方法的最大问题是我有一些需要拆箱的实际数据(而不是新类型)。但是,仅使用扩展名,我应该可以编写
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 时,这仍然(可能)不能解决我的问题。)
谢谢你的帮助!