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
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
There are actually three exponentiation operators:
(^)
,(^^)
and(**)
.^
is non-negative integral exponentiation,^^
is integer exponentiation, and**
is floating-point exponentiation: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 typeInt
. 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 noFractional
instance forInt
, 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 thePrelude
.^
requires its second argument to be anIntegral
. If I'm not mistaken, the implementation can be more efficient if you know you are working with an integral exponent. Also, if you want something like2 ^ (1.234)
, even though your base is an integral, 2, your result will obviously be fractional. You have more options so that you can have more tight control over what types are going in and out of your exponentiation function.Haskell's type system does not have the same goal as other type systems, such as C's, Python's, or Lisp's. Duck typing is (nearly) the opposite of the Haskell mindset.
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:
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:
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.