Reputation: 79
When using the native Data.Complex implementation in Haskell, constructing a complex number using non-fractional type using Int is possible. However, it is impossible to perform any calculation with it:
> let x = 1:+1 :: Complex Int
> x * x
<interactive>:44:1: error:
* No instance for (RealFloat Int) arising from a use of `*'
* In the expression: x * x
In an equation for `it': it = x * x
This becomes a problem when I am trying to use arbitrary significance structures like Data.Scientific since it has no instance for RealFloat as well. What can I do to remedy this situation? Writing an instance of RealFloat for Scientifc will result in an orphan instance. Should I write my own Complex class?
Upvotes: 2
Views: 93
Reputation: 476709
In order to perform functions defined in the Num
typeclass, the item a
of Complex a
should be a member of the RealFloat
typeclass. Indeed, the source code shows us:
-- | @since 2.01 instance (RealFloat a) => Num (Complex a) where -- … signum (0:+0) = 0 signum z@(x:+y) = x/r :+ y/r where r = magnitude z
Here the signum
is the culprit, since this returns x /r + y i / r
with r
the magnitude of the complex number. It basically normalizes the complex number to coordinates on a unit circle:
We determine the magnitude of a complex number with [src]:
magnitude :: (RealFloat a) => Complex a -> a magnitude (x:+y) = scaleFloat k (sqrt (sqr (scaleFloat mk x) + sqr (scaleFloat mk y))) where k = max (exponent x) (exponent y) mk = - k sqr z = z * z
Here the exponent :: RealFloat a => a -> Int
, this thus requires a
to ben an instance of the RealFloat
typeclass.
Since Num
defines several methods, it is sufficient that one of these methods has a type constraint, to enforce these constraint on the Num
class, and thus all the methods are defined in the Num
instance.
Writing an instance of RealFloat for Scientifc will result in an orphan instance.
You can make use of the toRealFloat :: RealFloat a => Scientific -> a
. We thus can work with:
Prelude Data.Scientific Data.Complex> let x = 1 :+ 1 :: Complex Scientific
Prelude Data.Scientific Data.Complex> let x' = toRealFloat <$> x
Prelude Data.Scientific Data.Complex> x' * x'
0.0 :+ 2.0
Upvotes: 1