
Evan's solution short-circuits: it does not execute the second action if the first succeeds. But your one runs both actions unconditionally.
Thanks for pointing that out! This is what happens when you only look at
the type of a function and *assume* its implementation:)
Actually this is a great way to shed light on the difference between
monadic and applicative: In the original function the context chaining
itself depends on a computed value (short circuiting), meaning it
"properly" relies on (>>=). liftM2 (<|>) - or rather liftA2 (<|>) - does
not, it doesn't unbox anything, so it cannot possibly be correct.
On 13 November 2014 01:23, Chris Wong
On Thu, Nov 13, 2014 at 11:07 AM, Andras Slemmer <0slemi0@gmail.com> wrote:
Well, "try" is really doing two things: chaining Maybes, and then adding a monadic context: try :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a) try = liftM2 (<|>) (You could weaken the assumption by using (Applicative m) instead)
That's different to Evan's original function.
Evan's solution short-circuits: it does not execute the second action if the first succeeds. But your one runs both actions unconditionally.
For example, the expression
try (return $ Just ()) (putStrLn "second action executed" >> return Nothing)
outputs "second action executed" with your solution, but not with Evan's.
The lesson is, applicative and monadic composition don't always yield the same results.
Chris