0

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?

Whelp
  • 103
  • 3

1 Answers1

6

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)
lisyarus
  • 15,025
  • 3
  • 43
  • 68
  • 2
    Isn't `foldr (+) 0` just a weird way to write `sum`? – melpomene Jan 26 '18 at 16:29
  • @melpomene Well, I just copy-pasted the original function, changing only the type declaration. Of course it is, but refactoring is another question. Thank you for a suggestion, though, I'll add some thoughts on refactoring. – lisyarus Jan 26 '18 at 16:30
  • @malpomene in fact, I simply wasn't aware of sum. Thanks for pointing it out. – Whelp Jan 26 '18 at 17:08
  • 3
    Even better: `sum [1/(z-x) | x<-zList, x/=z]`. Or, if it's ok to swap the arguments and make it a bit point-free, `sumInvZ z = sum . map (recip . (z-)) . filter (/=z)`. – leftaroundabout Jan 26 '18 at 17:12
  • @leftaroundabout Thank you, added your suggestions to the answer. – lisyarus Jan 26 '18 at 17:59