9
votes

I was reading an article about GHC 7.10.x Migration. There are some suggestions for fixing errors.

GHC says No instance for (Applicative ...)

If GHC complains that

Foo.hs:7:10: No instance for (Applicative Foo) arising from the superclasses of an instance declaration In the instance declaration for ‘Monad Foo’ then an easy way to fix this error is by defining an Applicative (and possibly a Functor) instance: instance Functor Foo where fmap = liftM -- or alternatively: -- fmap = m >>= pure . f

instance Applicative Foo where
    -- NB: DO NOT USE `pure = return`
    pure  = {- move the definition of `return` from the `Monad` instance here -}

    (<*>) = ap  {- defined in Control.Monad -}
    -- or alternatively:
    --  f1 <*> f2 = f1 >>= \v1 -> f2 >>= (pure . v1)

    -- NB: DO NOT USE `(*>) = (>>)`
    (*>) = {- move the definition of `>>` from the `Monad` instance here -}

instance Monad Foo where
    return = pure {- definition moved to `Applicative(pure)` -}

    (>>) = (*>) {- definition moved to `Applicative((*>))` -}

    {- ...retain other previous definitions... -}

There are the NBs: DO NOT USE `pure = return` and DO NOT USE `(*>) = (>>). Why can't one use it?

P.S. I tried to use it and it has been compiled.

1
This would lead to recursive definitions: the Monad instance functions are defined in terms of the Applicative instance functions, so you can't also go the other way.Will Sewell

1 Answers

7
votes

As @WillSewell hinted in the comment, from base-4.8.0.0 now return in type class Monad has a default implementation:

class Applicative m => Monad m where
    return      :: a -> m a
    return      = pure

By defining pure = return and forget to implement return manually one may create an infinite loop of definition which will pass the compilation and can only be detected at runtime.


>> is a different story for now. It has a default implementation relays on >>= only:

(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k

and by *> = >> you won't create an infinite loop unless you use *> in the definition of >>=, but there are some concern about the possible next major change in base (which may change the default implementation of >> to >> = *>) so *> = >> is discouraged for forward compatibility.