Haskell-需要为typeclass定义Vector2实例

时间:2018-10-12 11:11:09

标签: haskell

newtype Vector2 a = Vector2 (a,a)
     deriving (Show,Eq)

class VectorSpace v where
     vZero :: (Num a) => v a
     vSum :: (Num a) => v a -> v a -> v a
     vScalarProd :: (Num a) => a -> v a -> v a
     vMagnitude :: (Floating a) => v a -> a

需要将Vector2定义为类型VectorSpace的实例。

1 个答案:

答案 0 :(得分:2)

  

所以这是我到目前为止尝试过的:

instance VectorSpace (a,a) => VectorSpace Vector2 a
  vecZero = (0.0,0.0)
  vecSum (x,y) (x',y') = (x+x',y+y')

这里的第一个问题是语法。第一行的末尾需要一个where,如果假设Vector2 a是实例头,则需要在括号中加上

instance VectorSpace (a,a) => VectorSpace (Vector2 a) where

但是,这与声明的类的类型不匹配。

class VectorSpace (v :: * -> *) where
    vZero :: (Num a) => v a
    ...

,即,该类已经具有内置的假设,即v将应用于某些a参数。因此,实例头应该包含该参数,它看起来应该像

instance (...?) => VectorSpace Vector2 where

实际上,您在这里根本不需要任何约束。

instance VectorSpace Vector2 where

现在,关于方法

  vecSum (x,y) (x',y') = (x+x',y+y')

如果您的类型是元组类型,那将是一个非常明智的实现。但是,您的类型实际上是一个newtype包装的元组,并且newtypes始终需要显式构造函数。喜欢

  vecSum (Vector2 (x,y)) (Vector2 (x',y')) = Vector2 (x+x',y+y')

这确实有点愚蠢:您同时嵌套了一个命名构造函数和一个元组构造函数。由于元组会引起额外的间接访问(惰性,缓存),因此效率也很低。该类型最好定义为

data Vector2 a = Vector2 !a !a

在这里,由于字段严格,GHC可以将数字拆箱。在这种情况下,定义为

  vecSum (Vector2 x y) (Vector2 x' y') = Vector2 (x+x') (y+y')

Mind,正如我已经评论过的,对于向量空间类完全参数化v a来说,IMO 不好不好。在vector-space library中,不需要对实例进行参数化;优点之一是您可以直接为普通元组提供实例,而无需任何新类型包装。