这就是我要做的事情:
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 -> Int
和Double -> Double -> Double
。我认为我应该能够这样做,因为op类型为Num a => a -> a -> a
。
我的主要目标是抽象出功能Num子类中所需的重复:我更喜欢像在未注释版本中那样编写它。
答案 0 :(得分:8)
您对强制的定义会根据第一个定义将操作类型限制为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)