A more useful Monoid instance for Data.Map

Henning Thielemann lemming at henning-thielemann.de
Sat Apr 28 10:59:45 CEST 2012

On Fri, 27 Apr 2012, wren ng thornton wrote:

> On 4/27/12 9:04 PM, Daniel Peebles wrote:
>> Currently Data.Map has a Monoid instance, but it's rather lossy and not as
>> general as it could be:
>> instance (Ord k) =>  Monoid (Map k v) where
>>    mempty  = empty
>>    mappend = union
>>    mconcat = unions
>> The instance would be much nicer if it required a Monoid on v and used
>> unionWith mappend instead of just union.
> I'm inclined to agree as well.

I do not know whether I used the Monoid instance already, but I know that 
several times I used fromList by accident where I had to use fromListWith 

I think I would also prefer your instance because the current one silently 
drops information.

>> I realize that changing instances could break code, but I'd be curious
>> to see how many people even use the current monoid instance. Does
>> anyone have any system for testing hypotheses like this (by
>> typechecking a large randomized chunk of hackage or something)?
> The thing I'd be more worried about is silent changes to semantics. At least 
> if it doesn't typecheck then you know something went wrong; but there are 
> lots of monoids and so it's very likely to typecheck but to alter semantics.

I am also worried about such changes, at least I think that the major 
version number of 'containers' must be increased in order to raise 
awareness. There is at least a certain chance that uses of the old 
instance are detected, since the new instance requires a Monoid constraint 
on the 'v' type that was not there before.

> You could try removing the instance entirely and then see how much of Hackage 
> you can get to compile. That way you'll detect all uses, not just the uses 
> for non-monoidal value types. You should be able to get your hands on one of 
> the build-all-of-Hackage scripts people've used for this sort of thing in the 
> past.

This sounds like a good idea. However I suspect that a large portion of 
packages cannot be build together, because some of them rely on old 
compiler versions and other ones on new versions and even more packages 
rely transitively on installed foreign libraries.

Why is the Monoid instance important? Instead of mappend you can always 
use explicitly Map.union or (Map.unionWith mappend). I think the instance 
is important when combining different structures. E.g. in a Writer monad 
the written value must a Monoid. Thus a criterion for a useful Monoid 
instance could be: What is most useful for a Map as target value in a 
Writer monad?

More information about the Libraries mailing list