myLiftM2 :: Monad m => (a -> a1 -> m b) -> m a -> m a1 -> m b
myLiftM2 f x y = x >>= (\r1 -> y >>= (\r2 -> f r1 r2))
In liftM2 f return b, but myLiftM2 return m b
tl;dr: Use join :: Monad m => m (m a) -> m a
since a plain lift will return m (m a)
. E.g. write
join $ liftM2 f a b
But also...
liftM
s can also be written with Applicative
-- e.g.
liftM2 a b c == a <$> b <*> c
liftM3 a b c d == a <$> b <*> c <*> d
etc.
In this case, if you're willing to write in that style, you can write it cleanly and easily:
import Control.Applicative
myLiftM2 :: (Monad m, Applicative m) => (a -> a1 -> m b) -> m a -> m a1 -> m b
myLiftM2 f x y = join $ f <$> x <*> y
Edit:
As Daniel Wagner points out, you can just as easily write
join $ liftM2 a b c
as the equivalent
join $ a <$> b <*> c
My recommendation of the applicative style is for readability and is a separate point.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With