2012-11-23 36 views
2

這就是我想要做的事:解釋的功能具有多種類型的

data X = I Int | D Double deriving (Show, Eq, Ord) 

{- 
-- A normal declaration which works fine 
instance Num X where 
    (I a) + (I b) = I $ a + b 
    (D a) + (D b) = D $ a + b 
    -- ... 
-}           

coerce :: Num a => X -> X -> (a -> a -> a) -> X 
coerce (I a) (I b) op = I $ a `op` b 
coerce (D a) (D b) op = D $ a `op` b 

instance Num X where 
    a + b = coerce a b (+) 

編譯時我得到一個錯誤:

tc.hs:18:29: 
    Couldn't match type `Double' with `Int' 
    In the second argument of `($)', namely `a `op` b' 
    In the expression: I $ a `op` b 
    In an equation for `coerce': coerce (I a) (I b) op = I $ a `op` b 

coerce我想解釋op如同Int -> Int -> IntDouble -> Double -> Double。我想我應該能夠做到這一點,因爲op的類型是Num a => a -> a -> a

我的主要目標是抽象出功能Num子類中所需的重複:我寧願寫它,就像我在未註釋版本中一樣。

回答

8

您對coerce的定義將op的類型限制爲第一個定義爲Int -> Int -> Int,第二個限制爲Double -> Double -> Double。如果你真的想說op在所有Num類中都是多態的,那麼你應該使用Rank2Types來使它工作。

coerce :: X -> X -> (forall a . Num a => a -> a -> a) -> X 
coerce (I a) (I b) op = I $ a `op` b 
coerce (D a) (D b) op = D $ a `op` b 
coerce (I a) (D b) op = D $ op (fromIntegral a) b 
coerce (D a) (I b) op = D $ op a (fromIntegral b) 
+0

是的,謝謝我補充說。 – Satvik

+1

'Rank2Types'擴展名現在被棄用,應該使用'RankNTypes'。 ('Rank2Types'不能/不能保證只有排名2的類型被使用,它也會讓更高的排名類型被使用。我不確定Rank2Types是否被保留爲RankNTypes的同義詞,I認爲這個決定是反對它的。) –