Reputation: 2674
I'm trying to implement the example from the first chapter of this paper, which goes like this:
data Tree a = Fork (Tree a) (Tree a) | Leaf a | Nil deriving (Show)
instance Monad Tree where
return a = Leaf a
Nil >>= f = Nil
Leaf a >>= f = f a
Fork u v >>= f = Fork (u >>= f) (v >>= f)
tree1 = Fork
(Fork (Leaf 2) Nil)
(Fork (Leaf 2) (Leaf 3))
tree2 = Fork (Leaf 2) (Leaf 3)
f 2 = Fork Nil (Leaf "Two")
f 3 = Fork (Leaf "Three") (Leaf "String")
tree3 = tree2 >>= f
When I run it in GHC, I get this error:
monads.hs:3:10:
No instance for (Applicative Tree)
arising from the superclasses of an instance declaration
In the instance declaration for ‘Monad Tree’
Failed, modules loaded: none.
I've tried adding this to the beginning
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
but I get this error:
monads.hs:7:10:
Ambiguous occurrence ‘Monad’
It could refer to either ‘Main.Monad’, defined at monads.hs:1:1
or ‘Prelude.Monad’,
imported from ‘Prelude’ at monads.hs:1:1
(and originally defined in ‘GHC.Base’)
What is the most correct fix?
Upvotes: 3
Views: 2235
Reputation: 60463
To expand on Louis Wasserman's comment, you need to add an Applicative
(and therefore Functor
) instance now when you are declaring a Monad
instance. Once you have written the Monad
instance, the other instances are always the same:
import Control.Monad (liftM, ap)
instance Functor Tree where
fmap = liftM
instance Applicative Tree where
pure = return
(<*>) = ap
This changed because every Monad
is an Applicative
(using this instance), but not the other way around, so it's morally a superclass. However, Applicative
was added to the standard library after Monad
so it wasn't made a real superclass for a long time since that would break people's code. Recently, since Applicative
has come into very common use, the community decided to make Applicative
a real superclass of Monad
, breaking everybody's code once but improving it for the future. So that's what you're seeing.
Upvotes: 11
Reputation: 476719
The problem is that, like the documentation specifies. The Monad
class signature is:
class Applicative m => Monad m where
--...
This means that in order to define the instance of a type to be Monad
, you first need to define that type to be Applicative
. The problem is even more severe since the signature of Applicative
states:
class Functor f => Applicative f where
--...
So you first need to make Tree
an instance of Functor
. The reason that in the paper, this wasn't necessary, is because - as far as I know, in the early versions of Prelude
these constraints were not necessary.
Now in order to let it work, we first make Tree
an instance of Functor
. We therefore need to define a function fmap
, which - for a given function f :: a -> b
, maps a Tree a
to a Tree b
:
instance Functor Tree where
fmap f (Leaf a) = Leaf $ f a
fmap f (Fork u v) = Fork (fmap f u) (fmap f v)
fmap _ Nil = Nil
Now that we have defined this, we can define Applicative
:
instance Applicative Tree where
pure = Leaf
(<*>) (Leaf f) = fmap f
(<*>) Nil = const $ Nil
and finally we can define the Monad
instance:
instance Monad Tree where
return a = Leaf a
Nil >>= f = Nil
Leaf a >>= f = f a
Fork u v >>= f = Fork (u >>= f) (v >>= f)
Upvotes: 5