Icelandjack/deriving-via

Thoughts on how DerivingVia relates to all these Proposals

Icelandjack opened this issue · 4 comments

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?

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.

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

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

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.