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

GHC ghc-devs at haskell.org
Fri Aug 25 00:44:48 UTC 2017


#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


More information about the ghc-tickets mailing list