Polymorphic All type

base library exposes

newtype All = All { getAll :: Bool }

But in some cases it is useful to have an All which can contain a different type, so it would be nice to have instead:

newtype All bool = All { getAll :: bool }

An example is quickcheck, which could provide a Monoid instance for All Property (and Any Property). btw, a Monoid instance of Property was refused.

Are there any other libraries that could benefit from that (beside hedgehog)? Is it reasonable to hope for a polymorphic All in base?

1 Like

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.

2 Likes

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.

:+1:

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.

3 Likes

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)

Edit: I should have known there is already a proposal about this: https://gitlab.haskell.org/ghc/ghc/-/wikis/intrinsic-superclasses

1 Like