[Haskell-cafe] Map Monoid instance (was commutative monoid?)

Evan Laforge qdunkan at gmail.com
Sat Jun 25 19:07:46 CEST 2011

On Sat, Jun 25, 2011 at 9:00 AM, Jens Blanck <jens.blanck at gmail.com> wrote:
> I don't think the original question really is about commutativity, but
> rather the choice of Monoid instance.

Well, it was about two things, and that was one of them :)

>> > So there's a range of possible Monoid instances for each type,
>> More for some types than for others. For Maybe there are three:
>>  * always take the first/left value;
>>  * always take the last/right value;
>>  * or, use a semigroup operation defined on the values.
>> The first two options are provided by the First and Last newtypes, and the
>> third option is provided by the instance for Maybe itself (except that it
>> spuriously requires a Monoid instance instead of just a semigroup).
> But why does the Map instance of Monoid _not_ mimic the one chosen for
> Maybe. I claim this causes unnecessary surprises for users (and lifting the
> Monoid instance seems more useful, but that is harder to substantiate).

I'm guessing it's just historical happenstance.  Instances that were
introduced together, like the ones in Data.Monoid, show that thought
was definitely put in to how they interact with each other.  However
for Data.Map is in a different package and may well have been written
by a different person at a different time.  I was wondering about any
notions of "principal monoid" because I was wondering if there's any
way to have guidelines about monoid instances to avoid the "different
authors" effect.

For Data.Map, it's hard to say.  I have cases where I need both the
default instance and a mappend I wrote 'mappend = Map.unionWith
Monoid.mappend'.  I have Monoid instances where some fields use the
default "overriding" mappend, and some use the lifted version.  In the
case of the overriding version, you have to decide on which side to
merge the new monoid, and on the lifted one the two choices become
four, since you then have to decide whether the unionWith argument
should be flipped or not.  In practice, when I use the lifted mappend,
it's with commutative operators, so the multiplication of
possibilities doesn't matter.  So that's what started me down the
commutative path.

So I think the Data.Map choice is reasonable for that reason.  If it
were lifted, it would have to make a hard-coded decision about the
"side".  If you have to write your own, that's under your control.

More information about the Haskell-Cafe mailing list