问题描述
我有一个数据类型
newtype Zq q = Zq(IntType q)
其中'q'将是该类的一个实例
class Foo a where
type IntType a
和'IntType'只是与'q'相关的底层表示(即Int,Integral等)。
我想让Zq成为。我们目前使用上述链接中建议的约50行简单代码手动推导Unbox。我们将在代码中制作几种不同类型的'Unbox',因此为每种类型写50行不具有吸引力。
我发现了两种替代方法。另一种方法是使用使用模板Haskell派生Unbox的实例。 TH代码如下所示:
derivingUnboxZq
[d |实例(Foo q,U.Unbox(IntType q))=> Unbox'(ZqBasic q)(IntType q)|]
[| \(Zq x) - > x |]
[| \ x - > Zq x |]
问题是,我(或者我可以吗?)
[相关问题:为什么是FlexibleInstances隐含的扩展,不允许关联类型同义词实例?这个问题现在的解决方案是将Zq重新定义为:
<$ p
然后添加等式约束
i〜(IntType q)
在每个涉及(Zq qi)的情况下,这不是很优雅。我的(工作)Unbox派生成为
derivingUnboxZq
[d |实例(U.Unbox i,i〜IntType q,Foo q)=> Unbox'(Zq q i)i |]
[| \(Zq x) - > x |]
[| \ x - > Zq x |]
我觉得我应该可以做到这一点而不诉诸明确暴露类型'一世'。我所做的所有事情都是将其从关联类型同义词移动到具有相等约束的显式参数。为什么这个根本上是一种不同的(而且显然更安全)的方法?有没有什么办法可以避免添加类型参数'我',仍然会自动获得Unbox派生?
除了额外的类型参数,我无法使用TH包为(Vector r)派生Unbox,也就是我想制作Unbox向量的Unbox向量。我的尝试是这样的:
newtype Bar r = Bar(Vector r)
derivingUnboxBar
[d |实例(Unbox r)=> Unbox'(Bar r)(Vector r)|]
[| \(Bar x) - > x |]
[| \ x - > Bar x |]
但是我得到(很多)错误:
`basicUnsafeFreeze`不是类`Data.Vector.Generic.Base.Vector`类的(可见)方法
我不确定为什么它找不到这个方法,当它适用于我的Zq类型时。
第二种方法列出正在使用扩展GeneralizedNewtypeDeriving。我用这种方法看到的最大问题是我有一些实际的数据(而不是Newtype),我需要成为Unbox。然而,只要使用扩展名,我应该可以写出:
pre $ new $ q $ q $ Zq(IntType q)派生(Unbox, M.MVector MVector,G.Vector Vector)
或至少
newtype Zq qi = Zq i派生(Unbox,M.MVector MVector,G.Vector Vector)
$第一个导致错误:
没有实例for(p $ p
(M.MVector MVector(IntType q))
没有实例(G.Vector Vector((IntType q))由数据类型声明的`deriving`子句引起
IntType q))
第二个给出:
$ b (M.MVector MVector i)
没有用于(G.Vector U.Vector i)的实例
code>我不确定为什么它不能派生这些实例,因为上面的帖子让我相信它应该能够。也许我可以放弃使用与GeneralizedNewtypeDeriving相关的类型同义词? (这仍然(可能)不能解决我的问题,当我需要为数据派生Unbox。)
感谢您的帮助!
解决方案您在这里遇到几个单独的问题:
TH方法
是的,关联类型同义词的类实例是非法的
确实,您无法为关联类型定义类实例同义词或类型函数,这是有很好的理由:编译器无法分辨它们是否重叠。例如:
类型系列F a
实例Eq(F Int)
实例Eq(F Bool )
这些实例是否重叠?鉴于上述源代码,我们不能说:它取决于某人后来如何为 F 定义实例。例如,他们可以定义
类型实例F Int = Double
类型实例F Bool = Double
然后 Eq 的两个实例实际上会重叠。
你遇到 vector-th-unbox 包的问题
如果你看看你想要的实际的 Unbox 实例,你实际上并不希望为 IntType q ;你想要的只是这个:
instance(Unbox(IntType q),Foo q)=> Unbox(Zq q)其中
...
问题在于 vector-th-unbox 包迫使您使用假类型类 Unbox'来传递中间表示类型( IntType q ),这是滥用模板Haskell的语法来传递的一种便捷方式。然后GHC看到你写了 Unbox'(Zq q)(IntType q)并且抱怨。我建议为 vector-th-unbox 软件包提交一个错误。
$ bUnbox for Vector r
我认为Louis Wasserman报道了这一点。
GeneralizedNewtypeDeriving 方法
具体的编译错误是因为GHC无法推断适当的上下文。对于大多数类似于您所遇到的问题, StandaloneDeriving 语言扩展可以解决您的问题:
派生实例Unbox(IntType q)=> Unbox(Zq q)
派生实例Unbox(IntType q)=> M.MVector MVector(Zq q)
导出实例Unbox(IntType q)=> G.Vector Vector(Zq q)
但不要这样做!
虽然 GeneralizedNewtypeDeriving 通常完全符合您的要求,但在,它产生的 Unbox 实例是!所以在游说溧阳以解决目前的问题之后,坚持使用TH方法。
I have a datatype
newtype Zq q = Zq (IntType q)where 'q' will be an instance of the class
class Foo a where type IntType aand 'IntType' is just the underlying representation (i.e. Int, Integral, etc) associated with 'q'.
I want to make Zq an instance of Data.Vector.Unbox. We are currently manually deriving Unbox using about 50 lines of trivial code as suggested in the link above. We will be making several different types 'Unbox' in our code, so writing 50 lines for each type is not appealing.
I found two alternatives here. One alternative is to use this package which uses Template Haskell to derive instances of Unbox. The TH code would look like:
derivingUnbox "Zq" [d| instance (Foo q, U.Unbox (IntType q)) => Unbox' (ZqBasic q) (IntType q) |] [| \ (Zq x) -> x |] [| \ x -> Zq x |]The problem is, I can't define instances using associated type synonyms (or can I??)
[A related question: Why does TypeSynonymInstances, an extension implied by FlexibleInstances, not allow associated type synonym instances? Is this somehow fundamentally a different beast?]
My current solution to that problem is to redefine Zq as
newtype Zq q i = Zq iand then add the equality constraint
i~(IntType q)in every instance involving (Zq q i), which isn't very elegant. My (working) Unbox derivation becomes
derivingUnbox "Zq" [d| instance (U.Unbox i, i~IntType q, Foo q) => Unbox' (Zq q i) i |] [| \ (Zq x) -> x |] [| \ x -> Zq x |]I feel like I should be able to accomplish this without resorting to explicitly exposing the type 'i'. All I've done is moved it from an associated type synonym to an explicit parameter with equality constraints. Why is this "fundamentally" a different (and apparently safer) approach? Is there some way I can avoid adding the type parameter 'i' and still get automatic Unbox derivation?
Extra type parameter aside, I'm having trouble using the TH package to derive Unbox for (Vector r), that is, I want to make an Unbox Vector of Unbox Vectors. My attempt is something like:
newtype Bar r = Bar (Vector r) derivingUnbox "Bar" [d| instance (Unbox r) => Unbox' (Bar r) (Vector r) |] [| \ (Bar x) -> x |] [| \ x -> Bar x |]but I get (lots of) errors like:
`basicUnsafeFreeze` is not a (visible) method of class `Data.Vector.Generic.Base.Vector`I'm not sure why it can't find this method, when it works just fine for my Zq type.
The second approach listed above is using the extension GeneralizedNewtypeDeriving. The biggest problem I see with this approach is that I have some actual Data (rather than Newtype) that I need to be Unbox. However, just using the extension, I should be able to write
newtype Zq q = Zq (IntType q) deriving (Unbox, M.MVector MVector, G.Vector Vector)or at least
newtype Zq q i = Zq i deriving (Unbox, M.MVector MVector, G.Vector Vector)The first leads to the errors:
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)) ""and the second gives:
No instance for (M.MVector MVector i) "" No instance for (G.Vector U.Vector i) ""I'm not sure why it can't derive these instances, as the post above leads me to believe it should be able to. Perhaps I could get away with using the associated type synonym with GeneralizedNewtypeDeriving? (This still (probably) doesn't solve my problem when I need to derive Unbox for 'data's.)
Thanks for your help!
解决方案You're running into a few separate problems here:
The TH approach
Yes, class instances for associated type synonyms are illegal
It's true that you can't define class instances for associated type synonyms or type functions, and this is with good reason: the compiler can't tell whether they overlap. For instance:
type family F a instance Eq (F Int) instance Eq (F Bool)Do these instances overlap? Given the above source code, we can't tell: it depends on how someone later defines instances for F. For instance, they could define
type instance F Int = Double type instance F Bool = Doubleand then the two instances of Eq would in fact be overlapping.
You're running into a problem with the vector-th-unbox package
If you look at the actual Unbox instance you want, you don't actually want an instance for IntType q; what you want is simply this:
instance (Unbox (IntType q), Foo q) => Unbox (Zq q) where ...The problem is that the vector-th-unbox package forces you to use the fake type-class Unbox' to communicate the intermediate representation type (IntType q in your case), as a convenient way of abusing Template Haskell's syntax to pass in a type. And then GHC sees that you have written Unbox' (Zq q) (IntType q) and complains. I would suggest filing a bug for the vector-th-unbox package.
Unbox for Vector r
I think Louis Wasserman covered this.
The GeneralizedNewtypeDeriving approach
The specific compile error you're having is because GHC can't infer the appropriate context. For most problems similar to the one you're having, StandaloneDeriving language extension would solve your problem:
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)But DON'T do this!
While GeneralizedNewtypeDeriving often does exactly what you want, it is broken in some fundamental ways, and the Unbox instance it produces is completely broken! So stick with the TH approach, after lobbying Liyang for a fix for your current problem.
这篇关于使用关联的类型同义词自动推导Data.Vector.Unbox的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!