【发布时间】:2015-01-22 21:05:30
【问题描述】:
我有点不知道为什么 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`
有什么建议吗?提前致谢
【问题讨论】:
-
一方面,您希望您的函数
prodV适用于所有Num类型,但V0和Vn构造函数特别包含Float。其次,您是说V a中的a必须是Num,但Num a => [a]不是Num的实例。看起来您以错误的方式处理此问题。 -
您当然可以编写像
unV :: V a -> a这样的函数来简单地解开构造函数,但您的函数的前提似乎不正确。也许您应该考虑Vn :: [Float] -> V Float,但这将使unV :: V a -> a成为不可能,除非您首先以某种方式将Floats 列表转换为单个Float。 -
即使我删除了 Num 约束,错误仍然存在;我不太明白为什么 V0 和 Vn 构造函数不能“混合”..
-
@ocramz
V0 n的类型为V Float,而Vn ns的类型为V [Float]。它们不是相同的类型,但您在prodV的类型中指定它们必须相同。 GADT 构造函数上的模式匹配优化类型。 -
您的函数需要使用
Num函数,例如*和sum,因此您在类型签名中指定了您想要的Num a => V a。但是V的两个构造函数都是存在的,它们不能只保存任何类型的值。V0和Vn中包含的值不只是任何Num a => a,它们必须具有特定的类型。您不能使用V0和Float以外的任何值来构造值。同样,Vn必须使用[Float]类型的值构造。您试图告诉编译器V0 x和Vn y、x和y具有相同的类型,但根据定义它们不能。