Haskell中的exp x和类型签名

VH-*_*NZZ 4 haskell ghc ghci

exp'在GHCi中定义了自定义取幂函数:

let exp' x = sum $ take 100 [(x**k) / factorial k | k <- [0..]]
Run Code Online (Sandbox Code Playgroud)

产生以下类型签名:

#> :t exp'
exp' :: (Enum a, Floating a) => a -> a
Run Code Online (Sandbox Code Playgroud)

但是,我原以为它与exp函数的匹配,即

#> :t exp
exp :: Floating a => a -> a
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释Enum a => a我的exp'函数的类型约束吗?为什么不呢Floating a => a

谢谢.

GS *_*ica 6

它起源于k <- [0..]- 使用Enum该类的desugars .

然后它传播到最终类型签名,因为你正在使用(**)指数,它希望它的参数是相同的类型:

(**) :: Floating a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

一种选择是使用(^)取幂来代替:

(^) :: (Integral b, Num a) => a -> b -> a
Run Code Online (Sandbox Code Playgroud)

您还需要转换factorial k为正确的类型,例如fromIntegral:

exp' x = sum $ take 100 [(x^k) / fromIntegral (factorial k) | k <- [0..]]
Run Code Online (Sandbox Code Playgroud)

它可能更适合这种情况,因为你的指数将是整数,虽然它可能效率稍低,因为它使用重复乘法(指数中的对数)而不是恒定时间浮点运算.

或者(如评论中所示),坚持使用(**),用于fromIntegral从枚举移动Int到您正在使用的实际类型:

let exp' x = sum $ take 100 [(x**fromIntegral k) / fromIntegral (factorial k)
                                                        | k <- [0..]]
Run Code Online (Sandbox Code Playgroud)