Whelp
Whelp

Reputation: 103

Lifting a function from real numbers to complex numbers in Haskell

I wrote a function that takes a list and a number and returns a sum of shifted inverses:

sumInvZ::[Float]->Float->Float
sumInvZ zList z = let invList = [if z==x then 0 else 1/(z-x)|x<-zList] in foldr (+) 0 invList

I want to generalize this function to act on complex numbers as well. A simple solution is just to re-write it:

import Data.Complex

sumInvZC::[Complex Float]->Complex Float->Complex Float
sumInvZC zList z = let invList = [if z==x then 0 else 1/(z-x)|x<-zList] in foldr (+) 0 invList

But I'm also interested in making uses of the Complex monad to directly lift my SumInvZ. I've played around variations of liftM, but I've been unable to find a way to make it work. Is there a possibility?

Upvotes: 0

Views: 168

Answers (1)

lisyarus
lisyarus

Reputation: 15532

You can't use the Complex Monad or Functor for this, since those just operate on the complex number componentwise (note that componentwise multiplication and complex multiplication are totally different things).

Consider using the Fractional typeclass:

sumInvZ :: (Fractional f, Eq f) => [f] -> f -> f
sumInvZ zList z = let invList = [if z==x then 0 else 1/(z-x)|x<-zList] in
    foldr (+) 0 invList

By the way, you can rewrite the function in a bit more readable manner:

sumInvZ :: (Fractional f, Eq f) => [f] -> f -> f
sumInvZ zList z = sum [if z==x then 0 else 1/(z-x) | x <- zList]

Also consider two variants suggested by @leftaroundabout:

sumInvZ zList z = sum [1/(z-x) | x<-zList, x/=z]

or, swapping the arguments,

sumInvZ z = sum . map (recip . (z-)) . filter (/=z)

Upvotes: 6

Related Questions