PROPOSAL: Add Map/IntMap newtypes for different Monoid to containers

I would like to propose adding a newtype wrapper (with all relevant instances) for Map and IntMap (if I missed any other applicable type in containers, let me know). This newtype should differ in Monoid/Semigroup instance from Map/IntMap by switching: Ord k => Semigroup (Map k v) Ord k => Monoid (Map k v) to: (Ord k, Semigroup v) => Semigroup (Map k v) (Ord k, Monoid v) => Monoid (Map k v) or (Ord k, Semigroup v) => Monoid (Map k v) Any opinions on the overall idea? Opinions on which Monoid instance? Bikeshed for the newtype names? Cheers, Merijn

Please make your proposal more specific. (So that we can tear it apart, haha!) Seriously, I think it is to vague for starting a discussion. Best, Andreas On 24.03.2017 11:36, Merijn Verstraaten wrote:
I would like to propose adding a newtype wrapper (with all relevant instances) for Map and IntMap (if I missed any other applicable type in containers, let me know).
This newtype should differ in Monoid/Semigroup instance from Map/IntMap by switching:
Ord k => Semigroup (Map k v) Ord k => Monoid (Map k v)
to:
(Ord k, Semigroup v) => Semigroup (Map k v) (Ord k, Monoid v) => Monoid (Map k v) or (Ord k, Semigroup v) => Monoid (Map k v)
Any opinions on the overall idea? Opinions on which Monoid instance? Bikeshed for the newtype names?
Cheers, Merijn
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel@gu.se http://www.cse.chalmers.se/~abela/

Specifically, it's to add (let's use Foo as non-bikeshed name): newtype Foo k v = Foo (Map k v) deriving (...) instance (Ord k, Semigroup v) => Semigroup (Foo k v) where Foo m1 <> Foo m2 = Foo (Map.unionWith (<>) m1 m2) and corresponding Monoid (which would have 'mempty = Foo Map.empty'), deriving all other instances from Map. And the same for IntMap. I don't particularly care whether the Monoid instance should have a Semigroup or Monoid constraint on 'v'. I've personally created this newtype a bunch of times (as have others in #haskell, apparently), but I've never needed/wanted the current Monoid instance. Now I realise that changing the Monoid instance is not happening, so instead I would simply like to add a newtype that has the (to me) more useful Monoid instance. Cheers, Merijn
On 24 Mar 2017, at 11:59, Andreas Abel
wrote: Please make your proposal more specific. (So that we can tear it apart, haha!)
Seriously, I think it is to vague for starting a discussion.
Best, Andreas
On 24.03.2017 11:36, Merijn Verstraaten wrote:
I would like to propose adding a newtype wrapper (with all relevant instances) for Map and IntMap (if I missed any other applicable type in containers, let me know).
This newtype should differ in Monoid/Semigroup instance from Map/IntMap by switching:
Ord k => Semigroup (Map k v) Ord k => Monoid (Map k v)
to:
(Ord k, Semigroup v) => Semigroup (Map k v) (Ord k, Monoid v) => Monoid (Map k v) or (Ord k, Semigroup v) => Monoid (Map k v)
Any opinions on the overall idea? Opinions on which Monoid instance? Bikeshed for the newtype names?
Cheers, Merijn
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- Andreas Abel <>< Du bist der geliebte Mensch.
Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden
andreas.abel@gu.se http://www.cse.chalmers.se/~abela/

Hi Merijn,
I have seen unionWith (<>) used many times and it is indeed a useful
operation.
I also do not recall ever relying on the Monoid instance that's defined
currently.
However, I never needed a newtype wrapper.
Moreover, introducing a newtype just for the sake of the right Monoid
instance does not seem to be worth it.
For one I'd want to have all the other useful Map/Set functions (e.g.
lookup) defined on the newtype to not have to deal with wrapping/unwrapping
newtype. So for the newtype to really be useful, I guess you would have to
copy all the functions. I'm guessing this will introduce some maintenance
burden.
Besides you can't really add one newtype for all strict/lazy Map/IntMap.
Since `unionWith` is not a typeclass member, you'd have to resort to 4 (or
more) newtypes, one for each Map type. And you'd have to copy over all the
functions for each newtype...
I'd be really happy to see default Monoid instances changed, but I too
think that's not going to happen (at least anytime soon).
In the meantime unionWith (<>) seems reasonable enough.
Can you elaborate on how you benefited from a newtype?
Why unionWith (<>) was not enough?
Kind regards,
Nick
On Fri, 24 Mar 2017 at 14:39 Merijn Verstraaten
Specifically, it's to add (let's use Foo as non-bikeshed name):
newtype Foo k v = Foo (Map k v) deriving (...)
instance (Ord k, Semigroup v) => Semigroup (Foo k v) where Foo m1 <> Foo m2 = Foo (Map.unionWith (<>) m1 m2)
and corresponding Monoid (which would have 'mempty = Foo Map.empty'), deriving all other instances from Map. And the same for IntMap. I don't particularly care whether the Monoid instance should have a Semigroup or Monoid constraint on 'v'.
I've personally created this newtype a bunch of times (as have others in #haskell, apparently), but I've never needed/wanted the current Monoid instance. Now I realise that changing the Monoid instance is not happening, so instead I would simply like to add a newtype that has the (to me) more useful Monoid instance.
Cheers, Merijn
On 24 Mar 2017, at 11:59, Andreas Abel
wrote: Please make your proposal more specific. (So that we can tear it apart, haha!)
Seriously, I think it is to vague for starting a discussion.
Best, Andreas
On 24.03.2017 11:36, Merijn Verstraaten wrote:
I would like to propose adding a newtype wrapper (with all relevant instances) for Map and IntMap (if I missed any other applicable type in containers, let me know).
This newtype should differ in Monoid/Semigroup instance from Map/IntMap by switching:
Ord k => Semigroup (Map k v) Ord k => Monoid (Map k v)
to:
(Ord k, Semigroup v) => Semigroup (Map k v) (Ord k, Monoid v) => Monoid (Map k v) or (Ord k, Semigroup v) => Monoid (Map k v)
Any opinions on the overall idea? Opinions on which Monoid instance? Bikeshed for the newtype names?
Cheers, Merijn
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- Andreas Abel <>< Du bist der geliebte Mensch.
Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden
andreas.abel@gu.se http://www.cse.chalmers.se/~abela/
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

The reason that a newtype is needed is that Map and IntMap are already instances of Monoid, with the arguably wrong definition `(<>) = union`. If you want to use Map as a monoid with `<> = unionWith (<>)`, you need a newtype. If we could go back in time, we would just change the Monoid instance for Map itself, but that would invisibly break existing code. Twan On 2017-03-24 14:03, Nickolay Kudasov wrote:
Hi Merijn,
I have seen unionWith (<>) used many times and it is indeed a useful operation. I also do not recall ever relying on the Monoid instance that's defined currently. However, I never needed a newtype wrapper. Moreover, introducing a newtype just for the sake of the right Monoid instance does not seem to be worth it.
For one I'd want to have all the other useful Map/Set functions (e.g. lookup) defined on the newtype to not have to deal with wrapping/unwrapping newtype. So for the newtype to really be useful, I guess you would have to copy all the functions. I'm guessing this will introduce some maintenance burden.
Besides you can't really add one newtype for all strict/lazy Map/IntMap. Since `unionWith` is not a typeclass member, you'd have to resort to 4 (or more) newtypes, one for each Map type. And you'd have to copy over all the functions for each newtype...
I'd be really happy to see default Monoid instances changed, but I too think that's not going to happen (at least anytime soon). In the meantime unionWith (<>) seems reasonable enough.
Can you elaborate on how you benefited from a newtype? Why unionWith (<>) was not enough?
Kind regards, Nick
On Fri, 24 Mar 2017 at 14:39 Merijn Verstraaten
mailto:merijn@inconsistent.nl> wrote: Specifically, it's to add (let's use Foo as non-bikeshed name):
newtype Foo k v = Foo (Map k v) deriving (...)
instance (Ord k, Semigroup v) => Semigroup (Foo k v) where Foo m1 <> Foo m2 = Foo (Map.unionWith (<>) m1 m2)
and corresponding Monoid (which would have 'mempty = Foo Map.empty'), deriving all other instances from Map. And the same for IntMap. I don't particularly care whether the Monoid instance should have a Semigroup or Monoid constraint on 'v'.
I've personally created this newtype a bunch of times (as have others in #haskell, apparently), but I've never needed/wanted the current Monoid instance. Now I realise that changing the Monoid instance is not happening, so instead I would simply like to add a newtype that has the (to me) more useful Monoid instance.
Cheers, Merijn
> On 24 Mar 2017, at 11:59, Andreas Abel
mailto:abela@chalmers.se> wrote: > > Please make your proposal more specific. > (So that we can tear it apart, haha!) > > Seriously, I think it is to vague for starting a discussion. > > Best, > Andreas > > On 24.03.2017 11:36, Merijn Verstraaten wrote: >> I would like to propose adding a newtype wrapper (with all relevant instances) for Map and IntMap (if I missed any other applicable type in containers, let me know). >> >> This newtype should differ in Monoid/Semigroup instance from Map/IntMap by switching: >> >> Ord k => Semigroup (Map k v) >> Ord k => Monoid (Map k v) >> >> to: >> >> (Ord k, Semigroup v) => Semigroup (Map k v) >> (Ord k, Monoid v) => Monoid (Map k v) or (Ord k, Semigroup v) => Monoid (Map k v) >> >> Any opinions on the overall idea? Opinions on which Monoid instance? Bikeshed for the newtype names? >> >> Cheers, >> Merijn >> >> >> >> _______________________________________________ >> Libraries mailing list >> Libraries@haskell.org mailto:Libraries@haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > > > -- > Andreas Abel <>< Du bist der geliebte Mensch. > > Department of Computer Science and Engineering > Chalmers and Gothenburg University, Sweden > > andreas.abel@gu.se mailto:andreas.abel@gu.se > http://www.cse.chalmers.se/~abela/ _______________________________________________ Libraries mailing list Libraries@haskell.org mailto:Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On 24/03/17 07:38 AM, Merijn Verstraaten wrote:
Specifically, it's to add (let's use Foo as non-bikeshed name):
newtype Foo k v = Foo (Map k v) deriving (...)
instance (Ord k, Semigroup v) => Semigroup (Foo k v) where Foo m1 <> Foo m2 = Foo (Map.unionWith (<>) m1 m2)
and corresponding Monoid (which would have 'mempty = Foo Map.empty'), deriving all other instances from Map. And the same for IntMap. I don't particularly care whether the Monoid instance should have a Semigroup or Monoid constraint on 'v'.
I've personally created this newtype a bunch of times (as have others in #haskell, apparently), but I've never needed/wanted the current Monoid instance. Now I realise that changing the Monoid instance is not happening, so instead I would simply like to add a newtype that has the (to me) more useful Monoid instance.
You have +1 from me. I've written this newtype a couple of times already for local use. I'd suggest also adding another newtype at the same time: newtype LeftBiased k v = LeftBiased (Map k v) deriving (...) instance Ord k => Semigroup (LeftBiased k v) where LeftBiased m1 <> LeftBiased m2 = LeftBiased (Map.union m1 m2) Then a future release of containers could deprecate the current Monoid instance of Map, and a future future release could remove it completely, and a far future release could replace it with the correct one. One can dream.
On 24 Mar 2017, at 11:59, Andreas Abel
wrote: Please make your proposal more specific. (So that we can tear it apart, haha!)
Seriously, I think it is to vague for starting a discussion.
Best, Andreas
On 24.03.2017 11:36, Merijn Verstraaten wrote:
I would like to propose adding a newtype wrapper (with all relevant instances) for Map and IntMap (if I missed any other applicable type in containers, let me know).
This newtype should differ in Monoid/Semigroup instance from Map/IntMap by switching:
Ord k => Semigroup (Map k v) Ord k => Monoid (Map k v)
to:
(Ord k, Semigroup v) => Semigroup (Map k v) (Ord k, Monoid v) => Monoid (Map k v) or (Ord k, Semigroup v) => Monoid (Map k v)
Any opinions on the overall idea? Opinions on which Monoid instance? Bikeshed for the newtype names?
Cheers, Merijn
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- Andreas Abel <>< Du bist der geliebte Mensch.
Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden
andreas.abel@gu.se http://www.cse.chalmers.se/~abela/
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Merijn Verstraaten
I would like to propose adding a newtype wrapper (with all relevant instances) for Map and IntMap (if I missed any other applicable type in containers, let me know).
This newtype should differ in Monoid/Semigroup instance from Map/IntMap by switching:
Ord k => Semigroup (Map k v) Ord k => Monoid (Map k v)
to:
(Ord k, Semigroup v) => Semigroup (Map k v) (Ord k, Monoid v) => Monoid (Map k v) or (Ord k, Semigroup v) => Monoid (Map k v)
Any opinions on the overall idea? Opinions on which Monoid instance? Bikeshed for the newtype names?
For what it's worth, I provide precisely this in my monoidal-containers package [1]. Also, Edward Kmett provides a similar idea in his reducers package [2]. Cheers, - Ben [1] https://hackage.haskell.org/package/monoidal-containers [2] https://hackage.haskell.org/package/reducers-3.12.1/docs/Data-Semigroup-Unio...

If you have to choose between the two use Ben's code, reducers is in
hospice on life-support, and is unlikely to see anything more than a
maintenance release in the foreseeable future.
-Edward
On Fri, Mar 24, 2017 at 1:34 PM, Ben Gamari
Merijn Verstraaten
writes: I would like to propose adding a newtype wrapper (with all relevant instances) for Map and IntMap (if I missed any other applicable type in containers, let me know).
This newtype should differ in Monoid/Semigroup instance from Map/IntMap by switching:
Ord k => Semigroup (Map k v) Ord k => Monoid (Map k v)
to:
(Ord k, Semigroup v) => Semigroup (Map k v) (Ord k, Monoid v) => Monoid (Map k v) or (Ord k, Semigroup v) => Monoid (Map k v)
Any opinions on the overall idea? Opinions on which Monoid instance? Bikeshed for the newtype names?
For what it's worth, I provide precisely this in my monoidal-containers package [1]. Also, Edward Kmett provides a similar idea in his reducers package [2].
Cheers,
- Ben
[1] https://hackage.haskell.org/package/monoidal-containers [2] https://hackage.haskell.org/package/reducers-3.12.1/docs/ Data-Semigroup-Union.html
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Hi Ben, I personally already have an implementation of this I keep reusing, but then I was demonstrating a use of Monoids in #haskell-beginners and found myself again needing this, Cale also told me they have a similar implementation of Monoid for map. So I'm now aware of at least 6 implementations of exactly this instance. To me this means the current Monoid is a rather unfortunate choice (but I'm preemptively conceding the fight to fix that one). But I feel that is a stronger argument to move such a newtype into containers. Cheers, Merijn
On 24 Mar 2017, at 18:34, Ben Gamari
wrote: Merijn Verstraaten
writes: I would like to propose adding a newtype wrapper (with all relevant instances) for Map and IntMap (if I missed any other applicable type in containers, let me know).
This newtype should differ in Monoid/Semigroup instance from Map/IntMap by switching:
Ord k => Semigroup (Map k v) Ord k => Monoid (Map k v)
to:
(Ord k, Semigroup v) => Semigroup (Map k v) (Ord k, Monoid v) => Monoid (Map k v) or (Ord k, Semigroup v) => Monoid (Map k v)
Any opinions on the overall idea? Opinions on which Monoid instance? Bikeshed for the newtype names?
For what it's worth, I provide precisely this in my monoidal-containers package [1]. Also, Edward Kmett provides a similar idea in his reducers package [2].
Cheers,
- Ben
[1] https://hackage.haskell.org/package/monoidal-containers [2] https://hackage.haskell.org/package/reducers-3.12.1/docs/Data-Semigroup-Unio...
participants (7)
-
Andreas Abel
-
Ben Gamari
-
Edward Kmett
-
Mario Blažević
-
Merijn Verstraaten
-
Nickolay Kudasov
-
Twan van Laarhoven