ok so i've seen like 50 threads asking "why does my Monad instance need an Applicative instance" or "what even is Functor" or "what happened to fail" and i'm TIRED of it, so i'm writing the definitive megathread. please read this before posting a new thread, i will personally hunt you down with a proof of False if you don't nyaa~
βββ THE HIERARCHY βββ
The modern Haskell typeclass hierarchy (as of GHC 7.10+) looks like this:
This is the hierarchy you get today. Every Monad is an Applicative, every Applicative is a Functor. Mathematically clean. Logically sensible. Took us 25 years to get here. I am not joking.
βββ WHY WAS IT EVER BROKEN? βββ
The original Haskell 98 Monad class had no Functor or Applicative superclass constraint. This is because Applicative as a typeclass didn't even exist in Haskell 98 β it was introduced by McBride and Paterson in their 2008 paper "Applicative Programming with Effects". Functor existed but wasn't in the superclass chain because... nobody got around to it, honestly.
So people would write Monad instances without Functor instances (even though every Monad IS mathematically a functor via fmap f x = x >>= return . f). This was simply a historical accident β the standard class hierarchy was a consequence of Haskell's development, rather than logic.
βββ THE AMP (Applicative-Monad Proposal) βββ
The AMP (Applicative-Monad Proposal) was formally proposed for Haskell 2014 and implemented in GHC 7.10. It made Applicative a proper superclass of Monad. This was a BIG BREAKING CHANGE that required fixing thousands of packages on Hackage. The proposal was rolled out in phases:
- GHC 7.8: Warning phase β "your Monad has no Applicative instance"
- GHC 7.10: Full enforcement β Functor β Applicative β Monad hierarchy becomes law
After AMP, the classic question "A Monad is always an Applicative but due to historical reasons it's not β you can verify it by setting (<*>) = ap" became irrelevant. Now you just have to actually write the instance.
βββ THE fail SITUATION βββ
Oh boy. So fail was ALSO in the Monad class for years, used to handle pattern match failures in do-notation. The problem was that fail cannot be sensibly implemented for many monads β for State, Reader, and IO it would just call error, meaning Monad-polymorphic code could silently be non-total. This is terrible. The MonadFail proposal (MFP) extracted it into its own class:
Types like Either e, STM, State s, Reader r do NOT get MonadFail instances. Maybe and [] do, because they have sensible failure semantics (Nothing and [] respectively).
I'll stop here for the OP. More detail on Alternative, MonadPlus, and the lawfulness debates in the following posts nyaa~ please reply with your questions and i'll answer them here.