Icelandjack / deriving-via

Deriving via
33 stars 4 forks source link

Thoughts on how DerivingVia relates to all these Proposals #2

Closed Icelandjack closed 6 years ago

Icelandjack commented 6 years ago

I want some perspective on all of these proposals (AMP, Monad of not Return ..) & how they relate to DerivingVia:

  1. Can we say anything about the frequency of these proposals? Do we expect to see many more of them in the coming years?

  2. There seems to be a pattern (assuming “Monad of no return”) that goes something like

    1. Make Semigroup (Applicative) a superclass of Monoid (Monad). This continues to work:

      instance Monoid m => Semigroup (W m) where
        (<>) = mappend
      
      instance Monad m => Applicative (W' m) where
        pure = W' . return
        W' f <*> W' v = W' (f `ap` v)
    2. Move mappend (return) out of Monoid (Monad), but now how do we define (<>) (pure)?

    Between i and ii we have the option to use DerivingVia, but after it becomes circular (see #13876), we have to scrap W and add a Pointed to W'

    instance (Pointed m, Monad m) => Applicative (W' m) where
      pure = W' . point
      W' f <*> W' v = W' (f `ap` v)
  3. Can DerivingVia help?

RyanGlScott commented 6 years ago

I'm not sure if this is a good use case for deriving via or not. Ultimately, removing mappend/return/what-have-you from a class is a pretty significant change, and one that seems tricky to work around in a truly backwards-compatible fashion. After all, you're going to need to define the code for mappend/return/etc. somewhere—if not in Monoid/Monad/etc., then in another class.

In terms of using the least amount of CPP, the Pointed approach seems like the most promising, even if it is a tad awkward.

Icelandjack commented 6 years ago

I'm wondering if the pattern in i. ii. is the wrong way to go about it completely

Icelandjack commented 6 years ago

Maybe it's completely unrelated to deriving via, do you have any thoughts on this direction?

Where a potential superclass means "removing methods" from the subclass

-- Semigroup is "inlined" in Monoid
class Monoid m where
  mempty :: m
  mappend :: m -> m -> m

type Semigroup s = (Monoid s - mempty)

It doesn't result in the expected formulation (class Semigroup m => Monoid m where mempty :: m) but it is equivalent and means that nobody's code breaks. What is the type of mappend? Well that would still have a Monoid constraint, but could be given a less restrictive synonym:

(<>) :: Semigroup s => s -> s -> s
(<>) = mappend
RyanGlScott commented 6 years ago

We ended up including a discussion of this in the paper. The conclusion was that mappend/return/etc. being class methods was essential to make this trick work.