使用关联的类型同义词自动推导Data.Vector.Unbox

我有一个数据类型

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行不具吸引力。

我在这里找到了两个选择。 另一种方法是使用这个使用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)的情况下,这不是很优雅。 我的(工作)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',仍然可以自动获得Unbox派生?

抛开额外的类型参数,我无法使用TH软件包来为(Vector r)派生Unbox,也就是说,我想制作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类型时很好。


上面列出的第二种方法是使用扩展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时,仍然(可能)不能解决我的问题。)

谢谢你的帮助!


您在这里遇到一些单独的问题:

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。

Vector r Unbox

我认为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经常按照您的想法完成,但它在某些基本方面被打破,并且它产生的Unbox实例完全被破坏! 所以在游说溧阳解决你目前的问题之后,坚持使用TH方法。


我更改了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

链接地址: http://www.djcxy.com/p/86099.html

上一篇: Automatic derivation of Data.Vector.Unbox with associated type synonyms

下一篇: Given its body functions, create an instance of a type class (or workaround)