[GHC] #11135: Migrate more of Data.Functor.* from transformers to base.

GHC ghc-devs at haskell.org
Mon Dec 21 09:02:20 UTC 2015


#11135: Migrate more of Data.Functor.* from transformers to base.
-------------------------------------+-------------------------------------
        Reporter:  hvr               |                Owner:
            Type:  task              |               Status:  upstream
        Priority:  highest           |            Milestone:  8.0.1
       Component:  libraries/base    |              Version:  7.10.2
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):  Phab:D1543
       Wiki Page:                    |  Phab:D1544 Phab:D1630
-------------------------------------+-------------------------------------

Comment (by ekmett):

 Up until now we've avoided adding instances that would require extensions
 of that sort to base as they aren't suitable for describing in a language
 report without extending the language, and we lack a suitable precedent.

 Ultimately, we _had_ to move the classes from `Data.Functor.Classes` when
 we moved the other `Data.Functor.*` data types or we'd have wound up with
 orphan instances things that were previously perfectly sound and that are
 already seeing use. In the original Data.Functor migration proposal the
 inclusion of Data.Functor.Classes was offered up as a reluctant way to
 avoid random bikeshedding and loss of functionality during the migration
 of data types that truly belong further up the hierarchy, where we can
 avoid duplication of them and permit nicer extensions.

 On the other hand, we don't exactly have to go fishing for 3 dozen new
 classes to describe every other class 'one argument up'. There are viable
 solutions for folks who don't care about Haskell 98 (so long as they also
 don't care about the `Functor` concerns brought up above.)

 E.g. in my `constraints` package, using `ConstraintKinds` and `PolyKinds`,
 I supply

 {{{#!hs
 data Dict p where Dict :: p => Dict p
 newtype p :- q = Sub (p => Dict q)
 class Lifting p t where
   lifting :: p a :- p (t a)
 }}}

 Then everything from `Lifting Eq`, `Lifting Monad`, to `Lifting Monoid`
 all "just work". However, while more universal they aren't as effective as
 the manual dictionary passing done here. Such a pattern rules out some
 nice usecases, while simultaneously requiring a ridiculous number of
 instances to be defined by all users and a fair bit of sophistication to
 use.

 Consequently, I'm very much not advocating for something like that more
 radical approach.

 As for `Semigroup (Compose f g a)` -- we have an `Applicative (Compose f
 g)` because there is a canonical construction for nesting them. However,
 the choice of `Semigroup` here is quite open. You can't reason usefully
 about the instance you propose except instance by instance and there are
 multiple viable candidates. Let's consider `Monoid`:

 Given the existence of both:

 {{{#!hs
 instance (Applicative f, Applicative g, Monoid a) => Monoid (Compose f g
 a)
 instance Applicative (f (g a)) => Monoid (Compose f g a)
 }}}

 and the lack of a compelling motivation to pick one over the other, while
 one forces us to incur a flexible context, and the other requires a
 needless unit in the applicative structure when weakened to give the
 `Semigroup` constraint, I'd say it is better to supply neither instance.

 We've been meaning towards supplying instances when they are unambiguous
 and non-controversial. I'd say that such an instance for `Semigroup
 (Compose f g a)` would pass neither test.

 For right now I see the migration of the `Data.Functor.Classes` from
 `transformers` to `base` as more of a necessary evil than as a pattern to
 emulate, and trying to hit a decent compromise point, and I'd rather see
 if they see any sort of meaningful adoption outside of the `transformers`
 class hierarchy before we go and double/triple down on this design
 immediately.

 That said, as `Monoid` (now being in `Prelude`) and `Semigroup` in a few
 releases become more ingrained in our culture the idea of a `Monoid1` and
 `Semigroup1` to extend the consistency of this module might take better
 hold, but deciding that we want to do so probably belongs in the context
 of a much broader discussion in the libraries@ mailing list, rather than a
 rapidfire amendment in the last days before a release.

 E.g. is `Monoid1` sufficiently distinguished from `Applicative` to be
 worth defining? After all, you can likely prove that you need full
 parametricity in the argument, which would enable you to define an
 `Applicative` structure instead, meaning it likely doesn't add any
 expressive power, which would morally place `Semigroup1` at the same level
 as semi-applicative / `Apply` in the class hierarchy -- with nearly
 equivalent parametricity requirements. I personally find such structures
 useful, but I don't think there is community will to support a finer-
 grained AMP at this time.

 '''tl;dr''' My answer to your two questions could best be summaried as

 1.) Insofar as it prevents people from writing portable code if they want
 to and would break such code that already exists, then I think the answer
 is yes.

 2.) Even if you don't buy my reasoning in (1), unilaterally adding such an
 instance would rule out a potentially much more interesting discussion
 that should be had on libraries@ that I at least personally think would be
 more valuable.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11135#comment:20>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list