An alternative is getting a Semiring class into base as a superclass of Num and making the Monoid instances for Sum and Product depend on that semiring interface. Then Any would just be a type synonym of Sum Bool and All would be a type synonym of Product Bool.
As for other libraries that could benefit, I think embedded DSLs which define their own boolean type could benefit.
I would prefer a separate All and Sum just because it provides additional context; but I wouldn’t mind to have Sum Bool instance as well based on a Semiring class.
As for other libraeies that could benefit, I think embedded DSLs which define their own boolean type could benefit.
What are your thoughts on e.g. https://github.com/chessai/semirings ? I think enough people worked on it by now that it should be safe to consider it a standard.
It looks great, I see it even has Add and Mul newtypes which are equivalent to Sum and Product for Num instances. I think that the biggest problem left is figuring out how it can fit into the existing Num hierarchy with maximum backwards compatibility.
One drawback might be that people have to define an extra instance each time they want to write a Num instance. I would propose to make it possible to define superclass methods and creating superclass instance implicitly when defining an instance of a subclass.
E.g. consider the classes:
class Semiring a where
(+) :: a -> a -> a
zero :: a
(*) :: a -> a -> a
fromNatural :: Natural -> a
class Semiring a => Ring a where
negate :: a -> a
(-) :: a -> a -> a
fromInteger :: Integer -> a
I would propose that writing the following instance would be allowed and that it would also define an instance for Semiring:
instance Ring Integer where
(+) = (Integer.+)
zero = 0
(*) = (Integer.*)
one = 1
(-) = (Integer.-)
negate = Integer.negate
fromNatural = Integer.fromNatural
fromInteger = id
I think that that would also be very helpful for Monad, which would automatically define Functor and Applicative instances, and Monoid instances, which would automatically define Semigroup instances. Edit: actually DerivingVia a WrappedMonad or WrappedMonoid already covers these cases.
(I should probably write a proper GHC proposal for that)