Data.Vector.Unbox自动推导与相关类型同义词(Automatic derivation

2019-09-19 05:57发布

我有一个数据类型

newtype Zq q = Zq (IntType q)

其中,“Q”将是类的一个实例

class Foo a where
   type IntType a

和“IntType上”只是用“Q”相关联的基本表示(即中等,积分等)。

我想使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 |]

问题是,我使用相关联的类型的同义词不能定义实例 (或I可以??)

[一个相关的问题:为什么TypeSynonymInstances ,延伸通过FlexibleInstances暗示,不容许相关类型同义词实例? 这是莫名其妙本质上是一个不同的野兽?]

我目前的解决这一问题是重新定义为ZQ

newtype Zq q i = Zq i

然后添加等式约束

i~(IntType q)

在涉及(ZQ气),这是不是很优雅的每个实例。 我的(工作)的Unbox推导变

derivingUnbox "Zq"
  [d| instance (U.Unbox i, i~IntType q, Foo q) => Unbox' (Zq q i) i |]
  [| \ (Zq x) -> x |]
  [| \ x -> Zq x |]

我觉得我应该能够做到这一点,而不诉诸明确地暴露型“我”。 所有我所做的是从相关类型代名词移动它与等式约束明显的参数。 为什么这是“根本”不同的(显然更安全)的方法呢? 有一些方法可以让我避免增加类型参数“我”,仍然可以得到自动拆箱推导?

额外的类型参数不谈,我在使用的TH包导出的Unbox为(矢量R)的麻烦,那就是我想要的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为“数据的不解决我的问题。)

谢谢你的帮助!

Answer 1:

您正在运行到这里的几个不同的问题:

该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包。

UnboxVector 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它产生的实例是彻底打破 ! 因此随着TH办法坚持,游说溧阳为您的当前问题的修复程序后。



Answer 2:

我已经改变了语法4820b73 ,所以你应该能够做你现在想要什么:

derivingUnbox "Complex"
    [d| (Unbox a) ⇒ Complex a → (a, a) |]
    [| \ (r :+ i) → (r, i) |]
    [| \ (r, i) → r :+ i |]

我也已经固定了“xyz是不是一个(可见)方法...”错误在fe37976 ,虽然可以解决它:

import qualified Data.Vector.Generic
import qualified Data.Vector.Generic.Mutable

走出现在Hackage 。 CC:@reinerp



文章来源: Automatic derivation of Data.Vector.Unbox with associated type synonyms