This is a general question, not tied to any one piece of code.
Say you have a type T a
that can be given an instance of Monad
. Since every monad is an Applicative
by assigning pure = return
and (<*>) = ap
, and then every applicative is a Functor
via fmap f x = pure f <*> x
, is it better to define your instance of Monad
first, and then trivially give T
instances of Applicative
and Functor
?
It feels a bit backward to me. If I were doing math instead of programming, I would think that I would first show that my object is a functor, and then continue adding restrictions until I have also shown it to be a monad. I know Haskell is merely inspired by Category Theory and obviously the techniques one would use when constructing a proof aren't the techniques one would use when writing a useful program, but I'd like to get an opinion from the Haskell community. Is it better to go from Monad
down to Functor
? or from Functor
up to Monad
?
Functor
instances are typically very simple to define, I'd normally do those by hand.For
Applicative
andMonad
, it depends.pure
andreturn
are usually similarly easy, and it really doesn't matter in which class you put the expanded definition. For bind, it is sometimes benfitial to go the "category way", i.e. define a specialisedjoin' :: (M (M x)) -> M x
first and thena>>=b = join' $ fmap b a
(which of course wouldn't work if you had definedfmap
in terms of>>=
). Then it's probably useful to just re-use(>>=)
for theApplicative
instance.Other times, the
Applicative
instance can be written quite easily or is more efficient than the generic Monad-derived implementation. In that case, you should definitely define<*>
separately.I often choose a reverse approach as compared to the one in Abrahamson's answer. I manually define only the
Monad
instance and define theApplicative
andFunctor
in terms of it with the help of already defined functions in theControl.Monad
, which renders those instances the same for absolutely any monad, i.e.:While this way the definition of
Functor
andApplicative
is always "brain-free" and very easy to reason about, I must note that this is not the ultimate solution, since there are cases, when the instances can be implemented more efficiently or even provide new features. E.g., theApplicative
instance ofConcurrently
executes things ... concurrently, while theMonad
instance can only execute them sequentially due to the nature monads.I think you mis-understand how sub-classes work in Haskell. They aren't like OO sub-classes! Instead, a sub-class constraint, like
says "any type with a canonical
Monad
structure must also have a canonicalApplicative
structure". There are two basic reasons why you would place a constraint like that:For example, consider:
The first super-class constraint on
Norm
arises because the concept of a normed space is really weak unless you also assume a vector space structure; the second arises because (given a vector space) aNorm
induces aMetric
, which you can prove by observing thatis a valid
Metric
instance for anyV
with a validVector
instance and a validnorm
function. We say that the norm induces a metric. See http://en.wikipedia.org/wiki/Normed_vector_space#Topological_structure .The
Functor
andApplicative
super-classes onMonad
are likeMetric
, not likeVector
: thereturn
and>>=
functions fromMonad
induceFunctor
andApplicative
structures:fmap
: can be defined asfmap f a = a >>= return . f
, which wasliftM
in the Haskell 98 standard library.pure
: is the same operation asreturn
; the two names is a legacy from whenApplicative
wasn't a super-class ofMonad
.<*>
: can be defined asaf <*> ax = af >>= \ f -> ax >>= \ x -> return (f x)
, which wasliftM2 ($)
in the Haskell 98 standard library.join
: can be defined asjoin aa = aa >>= id
.So it's perfectly sensible, mathematically, to define the
Functor
andApplicative
operations in terms ofMonad
.I tend to write and see written the
Functor
instance first. Doubly so because if you use theLANGUAGE DeriveFunctor
pragma thendata Foo a = Foo a deriving ( Functor )
works most of the time.The tricky bits are around agreement of instances when your
Applicative
can be more general than yourMonad
. For instance, here's anErr
data typeAbove I defined the instances in
Functor
-to-Monad
order and, taken in isolation, each instance is correct. Unfortunately, theApplicative
andMonad
instances do not align:ap
and(<*>)
are observably different as are(>>)
and(*>)
.For sensibility purposes, especially once the Applicative/Monad Proposal is in everyone's hands, these should align. If you defined
instance Applicative (Err e) where { pure = return; (<*>) = ap }
then they will align.But then, finally, you may be capable of carefully teasing apart the differences in
Applicative
andMonad
so that they behave differently in benign ways---such as having a lazier or more efficientApplicative
instance. This actually occurs fairly frequently and I feel the jury is still a little bit out on what "benign" means and under what kinds of "observation" should your instances align. Perhaps some of the most gregarious use of this is in the Haxl project at Facebook where theApplicative
instance is more parallelized than theMonad
instance, and thus is far more efficient at the cost of some fairly severe "unobserved" side effects.In any case, if they differ, document it.
The magic here, that the Haskell uses the Kleisli-tiplet notation of a monad, that is more convenient way, if somebody wants to use monads in imperative programming like tools.
I asked the same question, and the answer come after a while, if you see the definitions of the Functor, Applicative, Monad in haskell you miss one link, which is the original definition of the monad, which contains only the join operation, that can be found on the HaskellWiki.
With this point of view you will see how haskell monads are built up functor, applicative functors, monads and Kliesli triplet.
A rough explanation can be found here: https://github.com/andorp/pearls/blob/master/Monad.hs And other with the same ideas here: http://people.inf.elte.hu/pgj/haskell2/jegyzet/08/Monad.hs