首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >关联类型同义词Data.Vector.Unbox的自动派生

关联类型同义词Data.Vector.Unbox的自动派生
EN

Stack Overflow用户
提问于 2012-07-09 16:20:44
回答 2查看 970关注 0票数 7

我有一个数据类型

代码语言:javascript
复制
newtype Zq q = Zq (IntType q)

其中'q‘将是类的一个实例

代码语言:javascript
复制
class Foo a where
   type IntType a

而'IntType‘仅仅是与'q’相关联的底层表示法(即Int,积分等)。

我想让Zq成为Data.Vector.Unbox的一个实例。我们目前正在使用大约50行普通代码手工派生Unbox,如上面的链接所建议的那样。我们将在代码中创建几个不同类型的“Unbox”,因此为每种类型编写50行并不吸引人。

我找到了两种选择这里。另一种选择是使用这个包裹,它使用模板Haskell派生Unbox的实例。TH代码看起来应该是:

代码语言:javascript
复制
derivingUnbox "Zq"
  [d| instance (Foo q, U.Unbox (IntType q)) => Unbox' (ZqBasic q) (IntType q) |]
  [| \ (Zq x) -> x |]
  [| \ x -> Zq x |]

问题是,我可以无法使用关联类型同义词定义实例 (或者我可以吗?)

[一个相关的问题:为什么TypeSynonymInstances ( FlexibleInstances所暗示的一个扩展)不允许关联的类型同义词实例?这是完全不同的野兽吗?]

我目前解决这个问题的方法是将Zq重新定义为

代码语言:javascript
复制
newtype Zq q i = Zq i

,然后添加相等约束。

代码语言:javascript
复制
i~(IntType q)

在涉及(Zq )的每一个实例中,这都不是很优雅。我的(工作)开箱派生变成

代码语言:javascript
复制
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向量。我的尝试是:

代码语言:javascript
复制
newtype Bar r = Bar (Vector r)

derivingUnbox "Bar"
  [d| instance (Unbox r) => Unbox' (Bar r) (Vector r) |]
  [| \ (Bar x) -> x |]
  [| \ x -> Bar x |]

但我会犯(很多)错误,比如:

代码语言:javascript
复制
`basicUnsafeFreeze` is not a (visible) method of class `Data.Vector.Generic.Base.Vector`

我不知道为什么它找不到这个方法,因为它对我的Zq类型很好。

列出的第二种方法是使用扩展上图。我看到这种方法最大的问题是,我有一些实际数据(而不是Newtype),我需要打开这些数据。但是,只要使用扩展,我就可以编写

代码语言:javascript
复制
newtype Zq q = Zq (IntType q) deriving (Unbox, M.MVector MVector, G.Vector Vector)

或者至少

代码语言:javascript
复制
newtype Zq q i = Zq i deriving (Unbox, M.MVector MVector, G.Vector Vector)

第一种导致错误:

代码语言:javascript
复制
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)) ""

第二条是:

代码语言:javascript
复制
No instance for (M.MVector MVector i) ""
No instance for (G.Vector U.Vector i) ""

我不知道为什么它不能导出这些实例,因为上面的帖子让我相信它应该能够。也许我可以通过使用与GeneralizedNewtypeDeriving相关联的类型同义词来解决问题?(当我需要为‘data’s派生Unbox时,这仍然(可能)不能解决我的问题。)

谢谢你的帮忙!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-10 22:10:44

您在这里遇到了几个单独的问题:

TH方法

是的,关联类型同义词的类实例是非法的。

确实,您不能为关联的类型同义词或类型函数定义类实例,这是有充分理由的:编译器无法判断它们是否重叠。例如:

代码语言:javascript
复制
type family F a
instance Eq (F Int)
instance Eq (F Bool)

这些实例是否重叠?考虑到上面的源代码,我们无法判断:这取决于以后某个人如何定义F的实例。例如,他们可以定义

代码语言:javascript
复制
type instance F Int = Double
type instance F Bool = Double

然后,Eq的两个实例实际上是重叠的。

您遇到了vector-th-unbox包的问题

如果查看所需的实际Unbox实例,实际上并不需要IntType q的实例;您想要的只是以下内容:

代码语言:javascript
复制
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语言扩展将解决您的问题:

代码语言:javascript
复制
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实例是完全破碎!所以,在游说李阳解决你当前的问题后,坚持第四种方法。

票数 3
EN

Stack Overflow用户

发布于 2012-11-18 06:35:38

我已经在4820b73中更改了语法,所以您现在应该能够做您想做的事情了:

代码语言:javascript
复制
derivingUnbox "Complex"
    [d| (Unbox a) ⇒ Complex a → (a, a) |]
    [| \ (r :+ i) → (r, i) |]
    [| \ (r, i) → r :+ i |]

我还修正了“xyz不是一个(可见的)方法…”fe37976中的错误,尽管可以使用:

代码语言:javascript
复制
import qualified Data.Vector.Generic
import qualified Data.Vector.Generic.Mutable

现在在刺伤上。CC:@reinerp

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11399143

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档