为什么Complex的乘法实现需要一个RealFloat?

sch*_*ine 3 haskell complex-numbers

在GHCi中,人们发现以下内容:

 import Data.Complex
 :t 2 * (3 :+ 4)
2 * (3 :+ 4) :: RealFloat a => Complex a
 :t (* (3 :+ 4))
(* (3 :+ 4)) :: RealFloat a -> Complex a -> Complex a
Run Code Online (Sandbox Code Playgroud)

然而:

 :t fmap (* 2) (3 :+ 4)
fmap (* 2) (3 :+ 4) :: Num a => Complex a -> Complex a
Run Code Online (Sandbox Code Playgroud)

现在,为什么会这样呢?难道只是fromIntegerNum a => Complex a已经键入RealFloat a => a -> Complex a?如果是这样,为什么?

sep*_*p2k 6

问题是,Complex a只有实例Num,如果a实例化RealFloat.那个Num实例被定义为:

instance RealFloat a => Num (Complex a) where
    ...
Run Code Online (Sandbox Code Playgroud)

由于*被定义的Num,你只能使用*一个Complex a,如果它的一个实例Num,也就是说,如果a是的一个实例RealFloat.

那么为什么Num实例有这个限制呢?

这是因为这种方法:

abs :: a -> a
Run Code Online (Sandbox Code Playgroud)

即使复数的两个分量都是整数,复数的绝对值也可以是非整数.例如,1 + 1i的绝对值是√2.因此abs :: Complex Integer -> Complex Integer无法定义方法(至少不能以产生正确结果的方式),因此不能Num (Complex Integer)定义完整的实例.所以只有一个用于RealFloats.

signum方法也是如此.