> 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 <lambda.fairy@gmail.com> wrote:
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