试图让我的GADT成为Num的一个实例,但是在构造函数之间遇到麻烦

时间:2013-10-19 23:53:36

标签: haskell

这是我的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 `*'

为什么会发生这种情况,我该如何解决?

1 个答案:

答案 0 :(得分:4)

(*) :: Num a => a -> a -> a,即参数必须属于同一类型;但ScalarVector构造函数为您提供了不同的类型。因此,可以为(*)Zero构造函数以及ScalarVector构造函数实现TVector,但不能为其组合实现。{ / p>

如果您希望v类型的Vector参数表示向量的元素类型,则只需更改VectorTVector构造函数以返回{{ 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

大概有一个更好的名字,它表达了你想要那些特殊限制的原因。