1

I wonder if Applicative is derived naturally through MonadTransformer's Monad

I had a hard time finding out if MaybeT's Monad and Applicative have the same context. As you can see in the link above.

The meaning of "same context" is

f <*> a = do
          x <- f
          y <- a
          return (x y)

I found a counter-example for MaybeT.

f = MaybeT [Nothing] :: MaybeT [] (Int -> Int)
a = MaybeT [Just 1, Just 2, Nothing] :: MaybeT [] Int

f <*> a = [Nothing, Nothing, Nothing]

do
x <- f
y <- a
return (x y)

= [Nothing]

So, it seems like there's a discord in MaybeT's Applicative and Monad.

How could we mix up >> , > , >>= . (<>) if there is a discord?

I can't believe it. If there is such a discrepancy, shouldn't there be a bug in the many Haskell codes currently using MaybeT?

kwonryul
  • 481
  • 3
  • 10
  • oh ho ho.... I got it.... MaybeT's (<*>) is different from ```Compose m Maybe```!!! Why?? – kwonryul Apr 17 '23 at 12:26
  • 2
    Yeah, `f <*> a` is actually only `[Nothing]` too. OTOH, `Compose [] Maybe` doesn't have a `Monad` instance at all. – leftaroundabout Apr 17 '23 at 13:43
  • 2
    In general, the composition of two monads is not always a monad. This is the reason why, as @leftaroundabout said, `Compose f g` doesn’t generally have a `Monad` instance, even when `f` and `g` are `Monad`s – David Young Apr 17 '23 at 14:44
  • 2
    In the book , Haskell programming from first principle, it says that <*> of ```MaybeT``` is same as ```Compose```'s applicative. It's wrong. I was confused about it. sorry for my mistake – kwonryul Apr 17 '23 at 15:12

2 Answers2

4

Quoting a comment:

MaybeT's (<*>) is different from Compose m Maybe

Indeed:

ghci> import Data.Functor.Compose 
ghci> import Control.Monad.Trans.Maybe 
ghci> f = MaybeT [Nothing] :: MaybeT [] (Int -> Int)
ghci> a = MaybeT [Just 1, Just 2, Nothing] :: MaybeT [] Int
ghci> f <*> a
MaybeT [Nothing]
ghci> Compose (runMaybeT f) <*> Compose (runMaybeT a)
Compose [Nothing,Nothing,Nothing]

As for how they differ, (<*>) for Compose is defined as:

Compose u <*> Compose v = Compose (liftA2 (<*>) u v)

If the two applicative functors being composed are also monads (as [] and Maybe are), we can express that in terms of their monad instances:

Compose (liftA2 (<*>) u v)

Compose $ do
    ui <- u  -- "i" is for "inner"
    vi <- v
    return (ui <*> vi)

Compose $ do
    ui <- u
    vi <- v
    return $ do
        f <- ui
        a <- vi
        return (f a)

Which, with the inner functor being Maybe, becomes:

Compose $ do
    ui <- u
    vi <- v
    return $ do
        f <- ui
        a <- vi
        Just (f a)

Whereas (<*>) for MaybeT is

mf <*> mx = MaybeT $ do
    mb_f <- runMaybeT mf
    case mb_f of
        Nothing -> return Nothing
        Just f  -> do
            mb_x <- runMaybeT mx
            case mb_x of
                Nothing -> return Nothing
                Just x  -> return (Just (f x))

Let's rephrase the right-hand side in a style closer to the one above:

MaybeT u <*> MaybeT v = MaybeT $ do
    ui <- u
    case ui of
        Nothing -> return Nothing
        Just f  -> do
            vi <- v
            case vi of
                Nothing -> return Nothing
                Just x  -> return (Just (f x))

(<*>) for Compose runs the outer effects before the inner ones, and so in your example you get the usual list (<*>) at the outer level, obtaining a list of 1 * 3 = 3 elements. (<*>) for MaybeT, however, runs the effects of its first argument (both the outer and the inner Maybe) before moving on to the second one, and that only if a Just is obtained, and so the Nothing lying in f in your example gives rise to merely another Nothing, resulting in [Nothing] overall.

duplode
  • 33,731
  • 7
  • 79
  • 150
2

As mentioned in the comments, the question has a false premise. The two expressions in the question,

f <*> a

and

do
  x <- f
  y <- a
  return (x y)

both produce the same result, MaybeT [Nothing].

You shouldn't be able to find examples in the wild where these two expressions differ for a single type. One of the laws listed in the Monad class is

m1 <*> m2 = m1 >>= (\x1 -> m2 >>= (\x2 -> return (x1 x2)))

which is just a desugaring of the identity you're trying to disprove. There are probably some examples out there of monads that break this law, but they're not "supposed" to.

amalloy
  • 89,153
  • 8
  • 140
  • 205