这是我的GADT:
data Vector v where
Zero :: (Num a, Eq a, Show a) => Vector a
Scalar :: (Num a, Eq a, Show a) => a -> Vector a
Vector :: (Num a, Eq a, Show a) => [a] -> Vector [a]
TVector :: (Num a, Eq a, Show a) => [a] -> Vector [a]
基本上,它表示包含属于类型Num,Eq和Show的元素的向量。
我希望Vector本身成为Num,所以我会做以下事情:
instance Num (Vector v) where
(Zero) + (Zero) = Zero
-- etc
(Vector a) * (Scalar b) = Vector $ map (* b) a -- This does not work
当我运行代码时,我得到:
Could not deduce (a ~ [a])
from the context (v ~ [a], Num a, Eq a, Show a)
bound by a pattern with constructor
Vector :: forall a. (Num a, Eq a, Show a) => [a] -> Vector [a],
in an equation for `*'
为什么会发生这种情况,我该如何解决?
答案 0 :(得分:4)
(*) :: Num a => a -> a -> a
,即参数必须属于同一类型;但Scalar
和Vector
构造函数为您提供了不同的类型。因此,可以为(*)
和Zero
构造函数以及Scalar
和Vector
构造函数实现TVector
,但不能为其组合实现。{ / p>
如果您希望v
类型的Vector
参数表示向量的元素类型,则只需更改Vector
和TVector
构造函数以返回{{ 1}}代替Vector a
:
Vector [a]
您还可以使用data Vector v where
...
Vector :: (Num a, Eq a, Show a) => [a] -> Vector a
TVector :: (Num a, Eq a, Show a) => [a] -> Vector a
扩展名缩写重复的类约束:
ConstraintKinds
大概有一个更好的名字,它表达了你想要那些特殊限制的原因。