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

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

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?

Cheers,
Merijn

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

Andreas Abel-2
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
> [hidden email]
> 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

[hidden email]
http://www.cse.chalmers.se/~abela/
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

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 <[hidden email]> 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
>> [hidden email]
>> 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
>
> [hidden email]
> http://www.cse.chalmers.se/~abela/

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

Nickolay Kudasov
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 <[hidden email]> 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 <[hidden email]> 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
>> [hidden email]
>> 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
>
> [hidden email]
> http://www.cse.chalmers.se/~abela/

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

Twan van Laarhoven
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 <[hidden email]
> <mailto:[hidden email]>> 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 <[hidden email]
>     <mailto:[hidden email]>> 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
>      >> [hidden email] <mailto:[hidden email]>
>      >> 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
>      >
>      > [hidden email] <mailto:[hidden email]>
>      > http://www.cse.chalmers.se/~abela/
>
>     _______________________________________________
>     Libraries mailing list
>     [hidden email] <mailto:[hidden email]>
>     http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
>
>
>
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
>
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

Ben Gamari-2
In reply to this post by Merijn Verstraaten
Merijn Verstraaten <[hidden email]> 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
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

signature.asc (497 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

Edward Kmett-2
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 <[hidden email]> wrote:
Merijn Verstraaten <[hidden email]> 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
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries



_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

Merijn Verstraaten
In reply to this post by Ben Gamari-2
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 <[hidden email]> wrote:
>
> Merijn Verstraaten <[hidden email]> 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
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

Mario Blažević-3
In reply to this post by Merijn Verstraaten
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 <[hidden email]> 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
>>> [hidden email]
>>> 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
>>
>> [hidden email]
>> http://www.cse.chalmers.se/~abela/
>
>
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries


_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Loading...