Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exponentiation in Haskell

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
like image 255
skytreebird Avatar asked Jun 19 '11 04:06

skytreebird


People also ask

What is mod in Haskell?

mod : Returns the modulus of the two numbers. This is similar to the remainder but has different rules when "div" returns a negative number.

What does the operator do in Haskell?

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).

What does Div do in Haskell?

div is a prefix operator that correctly performs integer division, throwing away the remainder.


3 Answers

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.

like image 167
Mikhail Glushenkov Avatar answered Nov 12 '22 06:11

Mikhail Glushenkov


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.

like image 29
augustss Avatar answered Nov 12 '22 06:11

augustss


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 of x^0 or x^^0 is 1 for any x, 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.

like image 42
Gabe Avatar answered Nov 12 '22 07:11

Gabe