Why no `instance (Monoid a, Applicative f)=> Monoid (f a)` for IO?

Edward Kmett ekmett at gmail.com
Tue Jul 15 02:55:36 UTC 2014


There are monads for which you want another Monoid, e.g. Maybe provides a
different unit, because it pretends to lift a Semigroup into a Monoid.

There are also monoids that take a parameter of kind * that would overlap
with this instance.

So we can't (and shouldn't) have the global Monoid instance like you give
there first.

As for the particular case of IO a, lifting may be a reasonable option
there.

A case could be made for adding an `instance Monoid a => Monoid (IO a)`,
but for such a ubiquitously used type, expect that this wouldn't be an easy
sell.

You'd possibly have to deal with everyone and their brother coming out of
the woodwork offering up every other Monoid they happened to use on IO.

Why?

IO provides a notion of failing action you could use for zero and you can
build an (<|>) like construction on it as well, so the 'multiplicative'
structure isn't the _only_ option for your monoid.

Even within the multiplicative structure using the monoid isn't necessarily
ideal as you might leak more memory with an IO a monoid that lifts () than
you would with working specifically on IO ().

You can argue the case that the choice you made is a sensible default
instance by instance, but when there isn't a real canonical choice we do
tend to err on the side of leaving things open as orphans are at least
possible, but once the choice is made it is very very hard to unmake.

I say this mostly so you know the kinds of objections proposals like this
usually see, not to flat out reject the idea of the particular case of this
instance for IO.

I will say the global 'instance (Applicative f, Monoid m) => Monoid (f m)'
won't fly for overlap reasons though.

-Edward


On Mon, Jul 14, 2014 at 6:55 PM, Brandon Simmons <
brandon.m.simmons at gmail.com> wrote:

> It seems to me that this should be true for all `f a` like:
>
>   instance (Monoid a, Applicative f)=> Monoid (f a) where
>       mappend = liftA2 mappend
>       mempty = pure mempty
>
> But I can't seem to find the particular `instance (Monoid a)=> Monoid
> (IO a)` anywhere. Would that instance be incorrect, or does it live
> somewhere else?
>
> FWIW I noticed this when I started thinking about an instance I wanted
> for 'contravariant':
>
>   instance (Monoid a, Applicative f)=> Monoid (Op (f a) b) where
>       mempty = Op $ const $ pure mempty
>       mappend (Op f) (Op g) = Op (\b-> liftA2 mappend (f b) (g b))
>
> at which point I realized (I think) all `f a` are monoidal, and so we
> ought to be able to get the instance above with just a deriving
> Monoid.
>
> Brandon
> _______________________________________________
> Glasgow-haskell-users mailing list
> Glasgow-haskell-users at haskell.org
> http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/glasgow-haskell-users/attachments/20140714/c8519f3b/attachment.html>


More information about the Glasgow-haskell-users mailing list