2012-05-23 50 views
7

以下代碼旨在生成Double或Integer。 s假定爲negateid;整個部分爲n;和f小數部分或Nothing爲整數。模式匹配後丟失多態性

computeValue :: Num a => (a->a) -> Integer -> (Maybe Double) -> Either Double Integer 
computeValue s n Nothing = Right $ s n 
computeValue s n (Just a) = Left $ s (fromIntegral n + a) 

當我編譯此,我得到:

test1.hs:2:28: 
    Couldn't match type `Integer' with `Double' 
    Expected type: Either Double Integer 
     Actual type: Either Double a 
    In the expression: Right $ s n 
    In an equation for `computeValue': 
     computeValue s n Nothing = Right $ s n 

test1.hs:2:38: 
    Couldn't match type `Integer' with `Double' 
    In the first argument of `s', namely `n' 
    In the second argument of `($)', namely `s n' 
    In the expression: Right $ s n 

好像莫名其妙的編譯器已經忘記了一個事實,即s是多態的。這裏發生了什麼?如何解決?

回答

10

s是不是從你的函數內部的多態:你可以使用一些Num例如在可以作爲該參數的功能,它可能是一個功能,僅適用於Complex!你需要的是一個普遍量化的函數s,即一個實際上可以用任何Num實例調用的函數。

{-# LANGUAGE Rank2Types #-} 

computeValue :: (forall a . Num a => a->a) -> Integer -> Maybe Double -> Either Double Integer 
computeValue s n Nothing = Right $ s n 
computeValue s n (Just a) = Left $ s (fromIntegral n + a) 

這工作那麼:

Prelude Data.Either> computeValue id 3 Nothing 
Right 3 
Prelude Data.Either> computeValue negate 57 (Just pi) 
Left (-60.1415926535898) 
+0

有趣!我發現什麼是錯的(它真的想要一個'a a a')作爲回報,但我沒有意識到有一種解決方法。 –

+6

@leftaroundabout:你實際上需要_universally_ quantified's'這就是2級簽名所做的。在這個例子中'ExistentialQuantification'沒有做任何事情,重要的擴展只是'Rank2Types'。 – Vitus

+0

@Vitus:啊,對!我不斷地把它混合起來,但這樣做更有意義,思考它。編輯。 – leftaroundabout