想象一下,我想定义一个向量空间类型类。我做了以下(灵感来自Yampa):
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
class Fractional (Groundfield v) => VectorSpace v where
type Groundfield v
(^+^) :: v -> v -> v
zeroVector :: v
(^*) :: v -> Groundfield v -> v
完美无缺。现在针对一些常见情况。当然,分数元组是一个向量空间:
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)
的实例定义,我本可以预期我已经匹配了该模式。显然不是!我怎样才能做到这一点?
答案 0 :(得分:1)
在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)