我有点不知道为什么以下的prodV中的最后一个模式不起作用:
{-# LANGUAGE GADTs #-}
data V a where
V0 :: Float -> V Float
Vn :: [Float] -> V [Float]
prodV :: (Num a) => V a -> V a -> a
prodV (V0 x) (V0 y) = x * y
-- prodV (Vn x) (Vn y) = zipWith (*) x y -- this one works
prodV (Vn xs) (Vn ys) = [ sum $ zipWith (*) xs ys ]
prodV (V0 n) (Vn ys) = map (* n) ys
GHCi 7.8.3抱怨:
Couldn't match type ‘Float’ with ‘[Float]’
Inaccessible code in
a pattern with constructor
Vn :: [Float] -> V [Float],
in an equation for ‘prodV’
In the pattern: Vn ys`
任何指针?提前谢谢
答案 0 :(得分:2)
嗯,GHC确切地告诉你问题是什么。根据您的定义,V0 something
始终具有V Float
类型(something
应为Float
类型 - 但这里不相关),而{{1}始终具有类型Vn anything
。但V [Float]
的类型签名指定两者具有相同的类型prodV
。因此,在这种情况下,V a
应该同时为a
和Float
,这是不可能的。
答案 1 :(得分:2)
签名
prodV :: (Num a) => V a -> V a -> a
强制要求两个参数都具有相同的类型参数,但如果您在V0
和Vn
上匹配,则参数必须包含V Float
和V [Float]
类型type参数不匹配。
我不太确定你想要什么语义,但我猜你想要将GADT定义为
data V n where
V0 :: n -> V n
Vn :: [n] -> V n
和你的功能
prodV :: (Num a) => V a -> V a -> V a
prodV (V0 x) (V0 y) = V0 $ x * y
prodV (Vn xs) (Vn ys) = Vn $ zipWith (*) xs ys
prodV (V0 n) (Vn ys) = Vn $ map (* n) ys
或可能
prodV' :: (Num a) => V a -> V a -> a
prodV' (V0 x) (V0 y) = x * y
prodV' (Vn xs) (Vn ys) = sum $ zipWith (*) xs ys
prodV' (V0 n) (Vn ys) = sum $ map (* n) ys
您能描述一下您希望函数prodV
实际执行的操作吗?原始代码中的类型对我来说并不合理。
答案 2 :(得分:0)
我只是想了解如何重载函数以模仿代数速记,但我想这不是正确的途径。 惯用的Haskell方法会做什么?例如。来自Numeric.Matrix:
adaptScalar f1 f2 f3 x y
| dim x == 1 = f1 (x@>0) y
| dim y == 1 = f3 x (y@>0)
| otherwise = f2 x y
instance Num (Vector Float) where
(+) = adaptScalar addConstant add (flip addConstant)
negate = scale (-1)
(*) = adaptScalar scale mul (flip scale)
signum = vectorMapF Sign
abs = vectorMapF Abs
fromInteger = fromList . return . fromInteger
根据操作数的维度选择运算符的正确实现(例如+或*)。