An expression like 2^(2%1)
does not typecheck in GHCi, and the error messages are cryptic. Why does this not work, what do I need to change?
I can't convert to another type, I want this for expressions like 27^(1%3)
.
An expression like 2^(2%1)
does not typecheck in GHCi, and the error messages are cryptic. Why does this not work, what do I need to change?
I can't convert to another type, I want this for expressions like 27^(1%3)
.
Haskell has three power operators:
(^) :: (Num a, Integral b) => a -> b -> a
This raises any type of number using a positive integral exponent.
You are getting an errors like Could not deduce (Integral (Ratio a0)) arising from a use of ‘^’
when typing 2^(2%3)
because Data.Ratio
is not an instance of Integral
. GHC sees that ^
wants an Integral
and notices Data.Ratio
cannot be used in such a situation.
(^^) :: (Fractional a, Integral b) => a -> b -> a
This operator allows negative integral exponents. Remember that x^(-n) == 1/(x^n)
. That's why it requires Fractional
.
Note that the exponent has to still be integral. 2^^(1%2)
would not be a Fractional
number.
(**) :: Floating a => a -> a -> a
This is the "catch all" operator. It can raise a fractional number to a fractional power. However this uses floating point numbers, not exact rationals.
Since we cannot represent all real numbers they have decided to simply rely on floats when you want inexact operations.
So you should use type conversions to perform that operation. A possible implementation could be:
realToFrac $ 27**(realToFrac $ 2%3) :: Rational
Or you may define a new operator:
(*^*) :: (RealFrac a, RealFrac b) => a -> b -> a
x *^* y = realToFrac $ realToFrac x ** realToFrac y
Which would allow you to write:
27 *^* (2%3)
I used two *
to remind of the **
which is used in the implementation and I've added a ^
to refer to the type of the first two operators... not sure whether that makes sense, or maybe ^**
or ^^*
would have been better.
However it may be better to simply use Double
s. It really depends on what the number represents and what you are doing with them.
To adress “why does this not work” – Haskell's multiple exponentiation operators actually reflect quite closely the way mathematicians define exponentiations!
^
implements, and it obviously works for any number type at all (because multiplication is always defined).Fractional
, you know! This is what ^^
does.Num a => a -> Rational -> Maybe a
. But the result would usually be Nothing
, so this would be a pretty useless function honestly. Implement it yourself if you like.Rational
is “infinitely accurate”, i.e. each value is really a single exact number. However, you can in reality only ever use a finite number of such rationals.Double
value represents a whole interval of real numbers, and if you take the unit of all those values you get not just a set of discrete points but the whole real line.Floating
class with its instance for Double
represents complete spaces, and why this class has the method (**) :: Floating a => a -> a -> a
.†In the complex numbers you can even define the logarithm of negative numbers, though it leads again to uniqueness problems.