Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are the liftM functions deprived of their monadic essence?

The difference between monad and applicative is that the former can choose the next computation depending on a previous result:

(\x -> if x == 1 then (\_ -> []) else (\y -> (\z -> \w -> [x,y,z]) =<< sqr) =<< (+1)) =<< (+1) $ 0
--                      ^

(\w x -> if x == 1 then (\_ _ -> []) else (\y z -> [x,y,z])) <*> (+1) <*> (+1) <*> sqr $ 0
--                        ^^^

The monadic computation can short circuit the computation whereas with the applicative one we have to use the entire computational structure and run all effects no matter what input we provide.

Let's compare this to liftM:

liftM3 (\x -> if x == 1 then (\_ _ -> []) else (\y z -> [x,y,z])) (+1) (+1) sqr $ 0
--                             ^^^

This seems to be applicative style in disguise. Even if I replace the lift operator with a monadic applicator, the whole structure seems to lose its monadic property:

appM3 w f x g y h z =
  f(\x' -> g(\y' -> h(\z' -> w x' y' z') z) y) x

appM3 (\x -> if x == 1 then (\_ _ _ -> []) else (\y z _ -> [x, y, z])) (=<<) (+1) (=<<) (+1) (=<<) sqr $ 0
--                            ^^^^^

Does this mean that a proper monadic computation must always be encoded manually? I know do notation but the underlying mechanism seems similar to macro expansion (please correct me if this is nonsense), so it doesn't really refute my assumption.

like image 351
Iven Marquardt Avatar asked Dec 17 '22 14:12

Iven Marquardt


1 Answers

You're right. liftM is just fmap, and liftM2 is just liftA2. Their existence is a historical artifact still fossilized in the standard libraries, rather than something that actually requires the power of the monadic bind operation.

Previous versions of the standard libraries did not make Functor and Applicative superclasses of Monad. (If you go back far enough, Applicative didn't even exist.) So for the sake of utility, functions that did the same things were created for using with Monad. They survived the transition in the Applicative-Monad proposal because they remain useful for one purpose - if you are implementing all the classes by hand, you can use them to implement the type's Functor and Applicative instances in terms of the Monad code.

like image 172
Carl Avatar answered Dec 22 '22 00:12

Carl