Can someone tell me why the Haskell Prelude defines two separate functions for exponentiation (i.e. ^
and **
)? I thought the type system was supposed to eliminate this kind of duplication.
Prelude> 2^2
4
Prelude> 4**0.5
2.0
mod : Returns the modulus of the two numbers. This is similar to the remainder but has different rules when "div" returns a negative number.
Haskell provides special syntax to support infix notation. An operator is a function that can be applied using infix syntax (Section 3.4), or partially applied using a section (Section 3.5).
div is a prefix operator that correctly performs integer division, throwing away the remainder.
There are actually three exponentiation operators: (^)
, (^^)
and (**)
. ^
is non-negative integral exponentiation, ^^
is integer exponentiation, and **
is floating-point exponentiation:
(^) :: (Num a, Integral b) => a -> b -> a (^^) :: (Fractional a, Integral b) => a -> b -> a (**) :: Floating a => a -> a -> a
The reason is type safety: results of numerical operations generally have the same type as the input argument(s). But you can't raise an Int
to a floating-point power and get a result of type Int
. And so the type system prevents you from doing this: (1::Int) ** 0.5
produces a type error. The same goes for (1::Int) ^^ (-1)
.
Another way to put this: Num
types are closed under ^
(they are not required to have a multiplicative inverse), Fractional
types are closed under ^^
, Floating
types are closed under **
. Since there is no Fractional
instance for Int
, you can't raise it to a negative power.
Ideally, the second argument of ^
would be statically constrained to be non-negative (currently, 1 ^ (-2)
throws a run-time exception). But there is no type for natural numbers in the Prelude
.
Haskell's type system isn't powerful enough to express the three exponentiation operators as one. What you'd really want is something like this:
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 **
This doesn't really work even if you turn on the multi-parameter type class extension, because the instance selection needs to be more clever than Haskell currently allows.
It doesn't define two operators -- it defines three! From the Report:
There are three two-argument exponentiation operations: (
^
) raises any number to a nonnegative integer power, (^^
) raises a fractional number to any integer power, and (**
) takes two floating-point arguments. The value ofx^0
orx^^0
is 1 for anyx
, including zero;0**y
is undefined.
This means there are three different algorithms, two of which give exact results (^
and ^^
), while **
gives approximate results. By choosing which operator to use, you choose which algorithm to invoke.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With