
On Sat, Jun 25, 2011 at 9:00 AM, Jens Blanck
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.