In “Learn You a Haskell for Great Good!” author claims that Applicative IO instance is implemented like this:
instance Applicative IO where
pure = return
a <*> b = do
f <- a
x <- b
return (f x)
I might be wrong, but it seems that both return, and do-specific constructs (some sugared binds (>>=) ) comes from Monad IO. Assuming that’s correct, my actual question is:
Why Applicative IO implementation depends on Monad IO functions/combinators?
Isn’t Applicative less powerfull concept than Monad?
Edit (some clarifications):
This implementation is against my intuition, because 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
Monadshould also be anApplicative, but this is not actually required, for historical reasons (i.e., becauseMonadhas been around longer). This is not the only peculiarity ofMonad, either.Consider the actual definitions of the relevant type classes, taken from the
basepackage’s source on Hackage.Here’s
Applicative:…about which we can observe the following:
Functor.Meanwhile, here’s
Monad:…about which we can observe the following:
Applicative, but alsoFunctor, both of which are logically implied byMonadbut not explicitly required.returnandjoin.failwhich doesn’t really fit in at all.In general, the ways that the
Monadtype 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 withApplicative, are a reflection of existing in a functional language; others, likefailor 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
Monadimplies an instance forApplicative, which in turn implies an instance forFunctor. A class context merely formalizes this explicitly; it remains true regardless. As it stands, given aMonadinstance, bothFunctorandApplicativecan be defined in a completely generic way.Applicativeis “less powerful” thanMonadin exactly the same sense that it is more general: AnyMonadis automaticallyApplicativeif you copy+paste the generalized instance, but there existApplicativeinstances which cannot be defined as aMonad.A class context, like
Functor f => Applicative fsays 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 withEqandOrd–the latter obviously implies the former, but you still need to define anEqinstance in order to define one forOrd.