(...) according to Typeclassopedia article it's required for a given type to be Applicative before it can be made Monad (or it should be in theory).
Yes, your parenthetical aside is exactly the issue here. In theory, any Monad
should also be an Applicative
, but this is not actually required, for historical reasons (i.e., because Monad
has been around longer). This is not the only peculiarity of Monad
, either.
Consider the actual definitions of the relevant type classes, taken from the base
package's source on Hackage.
Here's Applicative
:
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
...about which we can observe the following:
- The context is correct given currently existing type classes, i.e., it requires
Functor
.
- It's defined in terms of function application, rather than in (possibly more natural from a mathematical standpoint) terms of lifting tuples.
- It includes technically superfluous operators equivalent to lifting constant functions.
Meanwhile, here's Monad
:
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
fail :: String -> m a
...about which we can observe the following:
- The context not only ignores
Applicative
, but also Functor
, both of which are logically implied by Monad
but not explicitly required.
- It's also defined in terms of function application, rather than the more mathematically natural definition using
return
and join
.
- It includes a technically superfluous operator equivalent to lifting a constant function.
- It also includes
fail
which doesn't really fit in at all.
In general, the ways that the Monad
type class differs from the mathematical concept it's based on can be traced back through its history as an abstraction for programming. Some, like the function application bias it shares with Applicative
, are a reflection of existing in a functional language; others, like fail
or the lack of an appropriate class context, are historical accidents more than anything else.
What it all comes down to is that having an instance of Monad
implies an instance for Applicative
, which in turn implies an instance for Functor
. A class context merely formalizes this explicitly; it remains true regardless. As it stands, given a Monad
instance, both Functor
and Applicative
can be defined in a completely generic way. Applicative
is "less powerful" than Monad
in exactly the same sense that it is more general: Any Monad
is automatically Applicative
if you copy+paste the generalized instance, but there exist Applicative
instances which cannot be defined as a Monad
.
A class context, like Functor f => Applicative f
says two things: That the latter implies the former, and that a definition must exist to fulfill that implication. In many cases, defining the latter implicitly defines the former anyway, but the compiler cannot deduce that in general, and thus requires both instances to be written out explicitly. The same thing can be observed with Eq
and Ord
--the latter obviously implies the former, but you still need to define an Eq
instance in order to define one for Ord
.