Why does the power operator in F# only work for floating point numbers?

I have never seen a language have exponent or power operator only taking floating point numbers?

For example:

2 ** 2 throws an error The type 'int' does not support any operators named 'Pow'

Are there valid reasons for this design decision?


Solution 1:

(**) and pown are two different things. When you see (**), you can think of the mathematical formula using logarithms. When you see pown, it's just a series of multiplications. I understand it can be surprising/confusing at first, because most other languages don't make such a difference (mainly because integers are often implicitly converted to floating point values). Even in maths, there a small difference: See the Wikipedia entry, the first definition works only for positive integer exponents.

As they are two different (but related) things, they have different signatures. Here is (**):

^a -> ( ^b ->  ^a) when  ^a : (static member Pow :  ^a *  ^b ->  ^a)

And here is pown:

^a -> (int ->  ^a)
when  ^a : (static member get_One : ->  ^a) and
      ^a : (static member ( * ) :  ^a *  ^a ->  ^a) and
      ^a : (static member ( / ) :  ^a *  ^a ->  ^a)

If you create your own type, you only need to have your One, (*), and (/) to get it work with pown. The library will do the loop for you (it's optimized, it's not the naive O(n)).

If you want to use the (**) operator on your type for non-integral values, you'll have to write the full logic (and it's not be the same algorithm as in pown).

I think it was a good design decision to separate the two concepts.

Solution 2:

For integral powers, F# provides another operator: pown. Also, as a side note, both (**) and pown are overloaded, so it's perfectly possible to use them with other types which provide appropriate members (a static Pow method in the case of (**); (*) and (/) operators and a static One property in the case of pown).

I can't speak to why the F# team opted not to simulate a Pow member on int, but perhaps they didn't feel it was urgent since the pown operator could be used instead (and since it probably makes more sense to convert to float first in the case of big operands).

Solution 3:

The short answer is because it isn't very useful for integer types, even int64s. 2^26 only gives you ~1.84467441E19. So if you had two values X and Y both greater than say 19, then the power operator will result in an overflow.

I agree it is useful for small values, however it isn't generally useful for integer types.

Solution 4:

The language that F# is based on is OCaml which does not do operator overloading or automatic data coercion (they prefer explicit coercion).

Thus even adding doubles requires a different operator (+.). I'm not sure if this is where F# gets its strictness on it for sure but I am guessing it is.

In dynamic languages like Python or Scheme you would get automatic data coercion to a bigger data storage if the number was too big. For example you could have integers with integer exponents giving a big-integer for the result.

OCaml and F# have a spirit of extreme type safety.