我已经定义了以下 GADT:
data Vector v where
Zero :: Num a => Vector a
Scalar :: Num a => a -> Vector a
Vector :: Num a => [a] -> Vector [a]
TVector :: Num a => [a] -> Vector [a]
如果不是很明显,我正在尝试实现一个简单的向量空间。所有向量空间都需要向量加法,所以我想通过 makeVector
和instance
of来实现Num
。在向量空间中,添加不同长度的向量是没有意义的,这是我想要强制执行的。我认为这样做的一种方法是使用警卫:
instance Num (Vector v) where
(Vector a) + (Vector b) | length a == length b =
Vector $ zipWith (+) a b
| otherwise =
error "Only add vectors with the same length."
这种方法并没有什么问题,但我觉得必须有一种方法可以通过模式匹配来做到这一点。也许一种方法是定义一个新的数据类型VectorLength
,它看起来像这样:
data Length l where
AnyLength :: Nat a => Length a
FixedLength :: Nat a -> Length a
然后,可以将长度组件添加到Vector
数据类型中,如下所示:
data Vector (Length l) v where
Zero :: Num a => Vector AnyLength a
-- ...
Vector :: Num a => [a] -> Vector (length [a]) [a]
我知道这不是正确的语法,但这是我正在玩的一般想法。最后,您可以将添加定义为
instance Num (Vector v) where
(Vector l a) + (Vector l b) = Vector $ zipWith (+) a b
这样的事情是否可能,或者有没有其他方法可以为此目的使用模式匹配?