I am currently reading about the Alternative/MonadPlus typeclasses in wikibooks. It describes the difference very well. However, one puzzling part is the guard function, which I am assuming, is used for "short-circuiting" a computation. (Am I right?)
The function guard although defined in Control.Monad has an Alternative constraint, as following (link).
guard :: (Alternative f) => Bool -> f ()
guard True = pure ()
guard False = empty
But the above article, mentions that only the MonadPlus is required to enforce the left zero and right zero laws (Hence the stronger claim).
mzero >>= f = mzero -- left zero
m >> mzero = mzero -- right zero
Given the purpose of the guard function, shouldn't it be defined with a MonadPlus constraint? Don't we need the stronger laws if guard is supposed to "short-circuit" the computation? I am curious about the reason behind the specific design choice.
p.s.: I don't know what is a better way to describe the "cancelling the upfront computation" behavior other than the word "short-circuiting"?
guardhas anApplicativeconstraint because you don't need to perform monadic operations on it to define the function.It's definition is (copied from the Hackage source):
If it had specified
MonadPlusinstead ofAlternative, it wouldn't have gained anything.MonadPlusis a subclass ofAlternative, so allMonadPlusinstances can useguard, but not allAlternativescould use it.(Although there would be very few cases of excluded
Alternatives-- both cases mentioned here have an instance ofMonadPluseven though they don't satisfy the left-distributive rule.)In general, it's better to stick to the bare minimum restrictions needed to write a function, even if the intended use is more specific. This way, there is nothing excluded that shouldn't be, and no complaints from people whose types could work for it, but aren't monads.
Coincidentally, the Hoogle search results incorrectly show a
MonadPlusrestriction instead, though if you click the link it is correct.