That’s a good point, I hadn’t thought about that. Fewer type classes to maintain is definitely a positive. I think it’s also preferable from the perspective of understanding the API as a regular user, and not having odd corners which are only there for historical reasons. Also, if I’m reading code and I came across MonadZero for the first time, my first instinct would be to assume that since it’s a separate class, it ought to add something beyond just what’s provided by its superclasses, but in this case MonadZero would literally just be Alternative + Monad. So that’s potentially a bit misleading.
I think if we were going to keep MonadZero as a shorthand for Alternative + Monad, I’d still want to relax the constraint on
guard to Alternative, so I guess the only remaining question would be whether to provide a universal instance of the form
instance monadZero :: (Alternative f, Monad f) => MonadZero f
or leave it as-is so that downstream libraries have to declare the instances themselves. I guess probably the latter, since we would be trying to avoid breakage.
My guess (and this seems to be borne out by a quick code search on GitHub) would be that relatively little code will be broken by removing MonadZero, and in any case we can leave it there after deprecation for as long as we want to before removing it. I think deprecating it gets us the best of both worlds, as old code doesn’t break (since we are only relaxing existing constraints) and new code doesn’t need to reference MonadZero at all.