GHC在使用类型类时抱怨类型不匹配。

时间:2015-10-30 14:49:13

标签: haskell

我不明白为什么'dot'部分不起作用。

class Vector a where
    add, minus, cross :: a -> a -> a
    dot :: Num b => a -> a -> b

data Vector2D a = Vector2D a a deriving (Read)

instance Num a => Vector (Vector2D a) where
    add (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x1 + x2) (y1 + y2)
    minus (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x1 - x2) (y1 - y2)
    dot (Vector2D x1 y1) (Vector2D x2 y2) = x1*x2 + y1*y2

错误消息是:

Couldn't match expected type ‘b’ with actual type ‘a’
  ‘a’ is a rigid type variable bound by
      the instance declaration at example.hs:9:10
  ‘b’ is a rigid type variable bound by
      the type signature for
        dot :: Num b => Vector2D a -> Vector2D a -> b
      at example.hs:12:3
Relevant bindings include
  y2 :: a (bound at example.hs:12:37)
  x2 :: a (bound at example.hs:12:34)
  y1 :: a (bound at example.hs:12:20)
  x1 :: a (bound at example.hs:12:17)
  dot :: Vector2D a -> Vector2D a -> b (bound at example.hs:12:3)
In the first argument of ‘(*)’, namely ‘x1’
In the first argument of ‘(+)’, namely ‘x1 * x2’

我看一下点的类型,它是dot :: (Num b, Vector a) => a -> a -> b。我怎样才能做对吗?

1 个答案:

答案 0 :(得分:5)

问题是类型签名

dot :: Num b => a -> a -> b

表示dot需要能够返回任何数字类型,无论向量类型是什么,而表达式x1*x2 + y1*y2只返回放置的类型进入载体。

要解决此问题,您可以使用类型系列将单个标量类型连接到每个矢量类型:

{-# LANGUAGE TypeFamilies #-}

class Vector a where
    type ScalarOf a
    add, minus, cross :: a -> a -> a
    dot :: a -> a -> ScalarOf a

data Vector2D a = Vector2D a a deriving (Read)

instance Num a => Vector (Vector2D a) where
    type ScalarOf (Vector2D a) = a
    add (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x1 + x2) (y1 + y2)
    minus (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x1 - x2) (y1 - y2)
    dot (Vector2D x1 y1) (Vector2D x2 y2) = x1*x2 + y1*y2

另一种方法是使用多参数类型类,可能具有函数依赖性。

我还想提一下cross产品基本上只对三维向量有意义。 (我听说你可以使它们适用于7个维度,或者通常为1维。)