Re: [GHC] #1460: Problem with Monoid instance of Data.Map

#1460: Problem with Monoid instance of Data.Map -------------------------------------+------------------------------------- Reporter: ahey@… | Owner: (none) Type: proposal | Status: closed Priority: normal | Milestone: Not GHC Component: libraries/base | Version: 6.6.1 Resolution: fixed | Keywords: Data.Map | Monoid Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by andrewthad): I'd like to bring this up again. Especially since `Semigroup`, in the next two years, is going to end up as a superclass of `Monoid`. The even better instance would be: {{{ instance (Ord k, Semigroup v) => Monoid (Map k v) }}} In the mailing list that Joachim linked to, this kind of change seemed to attract pretty broad support. I think the only reasonable way to make this change without introducing silent breakage would be to release a `containers-0.6` in which `Map` has no `Monoid` instance. Then, in `containers-0.7`, the new instance would be introduced. This is precisely what Henning proposed in https://mail.haskell.org/pipermail/libraries/2012-April/017749.html, and I think it's the best option available for switching out this instance. These two release would need to be at least a year apart. We would probably like for their to be a stackage lts between them that had `containers-0.6`. And we would probably want to wait for `Semigroup` to actually become a superclass of `Monoid` in `base` before releasing `semigroups-0.7`, just because it's really annoying when you end up with a `(Semigroup v, Monoid v)` constraint sometimes. I would like to draw attention to the two arguments against making this change: 1. It would break a lot of other packages 2. The behavior value-combining `Monoid` instance is easily recovered by using `unionWith`. This reasoning roughly motivates this post: https://mail.haskell.org/pipermail/libraries/2012-April/017745.html Concerning argument (1), I offer no rebuttal. I'll only point out that, with stackage, we now have a somewhat convenient way to attempt to measure the breakage. But, no one has ever done this, and it might be worth looking into. Argument (2) I would like to challenge. In http://www.haskellforall.com/2014/07/equational-reasoning-at-scale.html, Gabriel Gonzalez uses, in a practical way, the behavior of data types that can lift monoidal value into another monoid. Things like: {{{ instance Monoid a => Monoid (IO a) instance (Monoid a, Monoid b) => Monoid (a,b) instance Monoid b => Monoid (a -> b) }}} These are useful because they give us `Monoid` instances for types like: {{{ Int -> Bool -> Char -> IO ([Text],Ordering) }}} The value-combining `Monoid` instance for `Map` is in this same spirit. It would allow us to trivially combine nested map with types like this: {{{ type M = Map Int (Map Char (Map PersonId (Map ItemId [Text]))) mappend :: M -> M -> M }}} This behavior can be recovered by `unionWith`, but it's a length explicit lifting: {{{ deepAppend :: M -> M -> M deepAppend = unionWith (unionWith (unionWith (unionWith (<>)))) }}} I plan on continuing this tomorrow. I have a little more to say. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/1460#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC