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的实例。
答案 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中,不需要对实例进行参数化;优点之一是您可以直接为普通元组提供实例,而无需任何新类型包装。