Haskell中的指数

时间:2011-06-19 04:33:08

标签: haskell exponent exponentiation

有人可以告诉我为什么Haskell Prelude为求幂定义了两个独立的函数(即^**)?我认为类型系统应该消除这种重复。

Prelude> 2^2
4
Prelude> 4**0.5
2.0

4 个答案:

答案 0 :(得分:119)

实际上有三个取幂运算符:(^)(^^)(**)^是非负积分求幂,^^是整数求幂,**是浮点求幂:

(^) :: (Num a, Integral b) => a -> b -> a
(^^) :: (Fractional a, Integral b) => a -> b -> a
(**) :: Floating a => a -> a -> a

原因是类型安全:数值运算的结果通常与输入参数具有相同的类型。但是,您无法将Int提升为浮点幂并获得Int类型的结果。因此,类型系统会阻止您执行此操作:(1::Int) ** 0.5会产生类型错误。 (1::Int) ^^ (-1)也是如此。

另外一种方法:Num类型在^下关闭(它们不需要有乘法反转),Fractional类型在^^下关闭, Floating类型已在**下关闭。由于Fractional没有Int个实例,因此无法将其提升为负值。

理想情况下,^的第二个参数将被静态约束为非负数(当前,1 ^ (-2)会抛出运行时异常)。但是Prelude中没有自然数字的类型。

答案 1 :(得分:28)

Haskell的类型系统不足以将三个求幂运算符表示为一个。你真正想要的是这样的:

class Exp a b where (^) :: a -> b -> a
instance (Num a,        Integral b) => Exp a b where ... -- current ^
instance (Fractional a, Integral b) => Exp a b where ... -- current ^^
instance (Floating a,   Floating b) => Exp a b where ... -- current **

即使打开多参数类型类扩展,这也不会起作用,因为实例选择需要比Haskell当前允许的更聪明。

答案 2 :(得分:10)

它没有定义两个运算符 - 它定义了三个!来自报告:

  

有三个双参数取幂运算:(^)将任意数字提升为非负整数幂,(^^)将小数提升为任何整数幂,(** })采用两个浮点参数。对于任何x^0x^^0x的值均为1,包括零; 0**y未定义。

这意味着有三种不同的算法,其中两种算法会给出精确的结果(^^^),而**会给出近似的结果。通过选择要使用的运算符,您可以选择要调用的算法。

答案 3 :(得分:4)

^要求其第二个参数为Integral。如果我没有弄错的话,如果你知道你正在使用积分指数,那么实现可以更有效率。此外,如果你想要像2 ^ (1.234)这样的东西,即使你的基数是一个积分,2,你的结果显然是分数。您有更多选项,以便您可以更加严格地控制进入和退出指数函数的类型。

Haskell的类型系统与其他类型系统没有相同的目标,例如C,Python或Lisp。鸭子打字(几乎)与哈斯克尔心态相反。