返回类型的GADT评估者

时间:2015-01-22 21:05:31

标签: haskell gadt

我有点不知道为什么以下的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`

任何指针?提前谢谢

3 个答案:

答案 0 :(得分:2)

嗯,GHC确切地告诉你问题是什么。根据您的定义,V0 something始终具有V Float类型(something应为Float类型 - 但这里不相关),而{{1}始终具有类型Vn anything。但V [Float]的类型签名指定两者具有相同的类型prodV。因此,在这种情况下,V a应该同时为aFloat,这是不可能的。

答案 1 :(得分:2)

签名

prodV :: (Num a) => V a -> V a -> a

强制要求两个参数都具有相同的类型参数,但如果您在V0Vn上匹配,则参数必须包含V FloatV [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

根据操作数的维度选择运算符的正确实现(例如+或*)。