3

After revisiting my MaybeT excercise I got warning that I should also have Applicative instance. I tried to implement it but got stuck as I cannot find way to apply m x to m f with Applicative m. Do I need Monad m?

newtype MaybeT m x = MaybeT { runMaybeT :: m (Maybe x) }

instance Functor m => Functor (MaybeT m) where
  fmap f m = MaybeT $ fmap z $ runMaybeT m where
    z (Just x) = Just $ f x
    z Nothing = Nothing

instance Applicative m => Applicative (MaybeT m)
sevo
  • 4,559
  • 1
  • 15
  • 31

2 Answers2

6

I think you do need Monad. Basically, if you have

f :: MaybeT m (a -> b)
x :: MaybeT m a

and if, when evaluating f <*> x, running the unwrapped f in m returns a Nothing, then the action for x shouldn't run at all - but you cannot achieve that without using that m is a Monad, since Applicative combinators intuitively always run all the subactions.

By the way, the simplest way to generate an Applicative just to satisfy the new AMP requirement, is to use

import Control.Monad (ap)

instance Applicative ... where
    pure = return
    (<*>) = ap

For Functor you can either use fmap = liftM, or the DeriveFunctor extension.

Ørjan Johansen
  • 18,119
  • 3
  • 43
  • 53
3

MaybeT could be defined as

newtype Compose f g x = Composed (f (g x))
newtype MaybeT m x = MaybeT (Compose m Maybe x)

and applicatives do compose. Hence you can write an applicative instance for MaybeT like this:

instance Applicative m => Applicative (MaybeT m) where
  pure = MaybeT . pure . Just
  f <*> x = MaybeT $ (<*>) <$> runMaybeT f <*> runMaybeT x

EDIT

As @Ørjan Johansen and @dfeuer explain, this is not a true instance for the MaybeT transformer, since the definition of (<*>) violates the f <*> x == ap f x law. Here is an example:

test :: MaybeT IO ()
test = MaybeT (return Nothing) <*> MaybeT (putStrLn "test" >> return Nothing)

main = runMaybeT test

This code prints test with my wrong definition and doesn't print anything with the right one.

Community
  • 1
  • 1
effectfully
  • 12,325
  • 2
  • 17
  • 40
  • 1
    The problem with this, as Ørjan Johansen explains in their answer, is that it doesn't short-circuit as expected—`runMaybeT x` will be run even if `runMaybeT f` produces `Nothing`. Of course, your application may not care, but this is incompatible with the `Monad` instance of `MaybeT m`. The laws for the classes specify that (at least "morally"), `(<*>)=ap`. So if you use this `Applicative` instance, you must use a matching `Monad` instance as well. – dfeuer Feb 14 '15 at 18:35
  • Er ... forget that deleted comment. I do think you probably should remove/modify the bit about "strictness", since this isn't a strictness issue, per se, although it can affect strictness. – dfeuer Feb 14 '15 at 20:01
  • @dfeuer, I haven't seen a comment about strictness, that's just my understanding of what's going on. The second argument of `(<*>)` is forced, while it shouldn't. Could you explain, what is wrong? – effectfully Feb 14 '15 at 20:20
  • 3
    Well, as your own example indicates, the issue is not that a thunk is *forced*, but rather that a monadic action is *executed*. – dfeuer Feb 14 '15 at 20:23
  • @dfeuer, I confused two concepts. Thanks again. – effectfully Feb 14 '15 at 20:42