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.