Haskell 如何使用类型族定义这些重叠实例?
假设我想定义一个向量空间类型类。我做了以下工作(受Yampa启发): 那很好用。现在来看一些常见的例子。当然,分数元组是一个向量空间:Haskell 如何使用类型族定义这些重叠实例?,haskell,typeclass,type-families,Haskell,Typeclass,Type Families,假设我想定义一个向量空间类型类。我做了以下工作(受Yampa启发): 那很好用。现在来看一些常见的例子。当然,分数元组是一个向量空间: instance Fractional a => VectorSpace (a,a) where type Groundfield (a,a) = a (a, b) ^+^ (c, d) = (a + c, b + d) zeroVector = (0,0) (a, b) ^* c
instance Fractional a => VectorSpace (a,a) where
type Groundfield (a,a) = a
(a, b) ^+^ (c, d) = (a + c, b + d)
zeroVector = (0,0)
(a, b) ^* c = (a * c, b * c)
更简单的是,分数是一个向量空间:
instance Fractional a => VectorSpace a where
type Groundfield a = a
(^+^) = (+)
zeroVector = 0
(^*) = (*)
每个实例本身都是完全有效的。但是如果我把它们放在同一个模块中,我会遇到这个问题:
VectorSpielwiese.hs:15:10:
Conflicting family instance declarations:
Groundfield (a, a) -- Defined at VectorSpielwiese.hs:15:10
Groundfield a -- Defined at VectorSpielwiese.hs:21:10
我意识到,在第二个实例定义中,匹配a
也会捕获元组模式。但是如果我以前为(a,a)
编写实例定义,我会认为我已经匹配了该模式。显然不是!我如何才能做到这一点?在GHC(相对而言)新型封闭式系列的帮助下,我认为我们可以实现这一目标。以下是所有类型检查:
type family Groundfield v where
Groundfield (a,a) = a
Groundfield a = a
class Fractional (Groundfield v) => VectorSpace v where
(^+^) :: v -> v -> v
zeroVector :: v
(^*) :: v -> Groundfield v -> v
instance (Fractional (Groundfield a), Num a, a ~ Groundfield a) => VectorSpace a where
(^+^) = (+)
zeroVector = 0
(^*) = (*)
instance Fractional a => VectorSpace (a,a) where
(a, b) ^+^ (c, d) = (a + c, b + d)
zeroVector = (0,0)
(a, b) ^* c = (a * c, b * c)
除非将第二个实例更改为具有新类型包装器,或者将
GroundField
更改为数据族,否则不能这样做。我怀疑这两个都不是你想要的。在这种情况下通常采用的方法是有一个“默认”实现,它对应于这个“普通”向量空间,然后您只需编写实例向量空间Float;实例向量空间双精度代码>。为此,您可能需要DefaultSignatures
。这就是为什么:它为Float
,Double
CIntMax
并且只使复合实例具有多态性。@leftaroundabout,是的,那是我开始分叉的时候,我想“这是很多重复。让我们改进一下。”@Turion:是的,这确实是非常机械的重复,你可以用一个简单的CPP宏很好地实现它。我同意这不太好。。。基本上,我们想要的是一个单独的实例,它适用于一组封闭的类型,也许您可以使用它更好地实现实例。哇!但是,如果这两个实例位于不同的模块中,该怎么办?闭合类型族强制同时声明Groundfield的所有实例。但是向量空间的实例可以在任何地方声明。
type family Groundfield v where
Groundfield (a,a) = a
Groundfield a = a
class Fractional (Groundfield v) => VectorSpace v where
(^+^) :: v -> v -> v
zeroVector :: v
(^*) :: v -> Groundfield v -> v
instance (Fractional (Groundfield a), Num a, a ~ Groundfield a) => VectorSpace a where
(^+^) = (+)
zeroVector = 0
(^*) = (*)
instance Fractional a => VectorSpace (a,a) where
(a, b) ^+^ (c, d) = (a + c, b + d)
zeroVector = (0,0)
(a, b) ^* c = (a * c, b * c)