Haskell Multiplication of a Complex Double with a Double

I was a bit surprised when the following code did not compile:

-- Code 1 import Complex type Velocity = Complex Double type Force = Complex Double type FrictionCoeff = Double frictionForce :: FrictionCoeff -> Velocity -> Force frictionForce mu vel = mu * vel 

Error says

 Couldn't match expected type `Complex Double' with actual type `Double' Expected type: Force Actual type: FrictionCoeff In the first argument of `(*)', namely `mu' In the expression: mu * vel 

So shorter

 -- Code 2 let z = 1 :+ 2 z * 3 -- Goes fine. z * 2.5 -- Goes fine. z * (2.5 :: Double) -- Explodes. 

The complex defines (*) as

 instance (RealFloat a) => Num (Complex a) where (x:+y) * (x':+y') = (x*x'-y*y') :+ (x*y'+y*x') 

Why do 3 (Num a => a) and 2.5 (Fractional a => a) match the pattern (x: + y), but Double can't?

+6
source share
2 answers

First, the type of multiplication operator

 (*) :: Num a => a -> a -> a 

which means that you can only multiply numbers of the same type , so multiplying Complex Double by Double will not work.

So why do you need to multiply a complex number with a decimal literal?

This works because numeric literals are polymorphic in Haskell, so when you enter an integer literal like 42 , it really means fromInteger 42 . Similarly, decimal literals such as 2.3 become fromRational (23 % 10) . If you learn the types of these functions,

 fromInteger :: Num a => Integer -> a fromRational :: Fractional a => Rational -> a 

this means that integer literals can be any numeric type, while decimal literals can be any fractional type. Complex numbers are both, so both z * 3 and z * 2.5 work.

When you are not dealing with literals, you need to convert. For example, your original function can be fixed by writing:

 frictionForce :: FrictionCoeff -> Velocity -> Force frictionForce mu vel = (mu :+ 0) * vel 

Finding the right conversion function is easy using Hoogle , as you can search for functions by type. In this case, searching Double -> Complex Double gives (:+) as the top result.

+15
source

You cannot multiply a real number by a complex number, even in "real math"; when you want to take 2 * (2 + 3i) , what you are actually calculating is (2 + 0i) * (2 + 3i) . Similarly, in Haskell, when you say:

 let z = 1 :+ 2 z * 3 

... then 3 is converted to Complex Double , making the imaginary part zero. This only happens for alphabetic numbers ( 2 , 3.141 , etc.) due to the overloaded literal functionality of Haskell; since literals do not have a default type (they can represent values โ€‹โ€‹of any type of number), Haskell can say that 3 is of type Complex Double in this context, and the corresponding conversion functions are called automatically.

If you want to do this conversion manually, that is, to make a complex number from a real number, which is a variable or otherwise already has a different fixed type, you should use the realToFrac function, which converts any real number to any fractional number (and Complex in this case is considered fractional number).

 z * realToFrac (2.5 :: Double) 

You can, of course, manually add :+ 0 if that looks neat to you.

+7
source

Source: https://habr.com/ru/post/911858/


All Articles