Should Generically (/ Generically1) derive newtype Generic (/ Generic1)?
Regarding #17147 (closed) (!5726 (closed)), this may be controversial and touch on the philosophy of Generic. "Generic" is universally derived using the stock deriving strategy. I propose deriving those instances for Generically{,1}
using generalized newtype deriving, by reusing the underlying Generic{,1}
instances. This is in line with all other instances for Generically{,1}
as they are defined using the generic representation of the underlying type.
type Generically :: Type -> Type
newtype Generically a = Generically a
deriving
newtype Generic
type Generically1 :: (k -> Type) -> k -> Type
newtype Generically1 f a = Generically1 (f a)
deriving
newtype Generic1
That is to say be given the following instance
instance Generic a => Generic (Generically a) where
type Rep (Generically a) = Rep a
from :: Generically a -> Rep a b
from (Generically a) = from a
to :: Rep a b -> Generically a
to = Generically . to
instance Generic1 f => Generic1 (Generically1 f) where
type Rep1 (Generically1 f) = Rep1 f
from1 :: Generically1 f a -> Rep1 f a
from1 (Generically1 as) = from1 as
to1 :: Rep1 f a -> Generically1 f a
to1 = Generically1 . to1
The other instances avoid newtype wrapping
Generically a <> Generically b = Generically (to (from a <> from b :: Rep a ()))
mempty = Generically (to (mempty :: Rep a ()))
fmap f (Generically1 as) = Generically1 (to1 (fmap f (from1 as)))
a <$ Generically1 as = Generically1 (to1 (a <$ from1 as))
pure a = Generically1 (to1 (pure a))
Generically1 fs <*> Generically1 as = Generically1 (to1 (from1 fs <*> from1 as))
liftA2 (·) (Generically1 as) (Generically1 bs) = Generically1 (to1 (liftA2 (·) (from1 as) (from1 bs)))
empty = Generically1 (to1 empty)
Generically1 as1 <|> Generically1 as2 = Generically1 (to1 (from1 as1 <|> from1 as2))
--->
a <> b = to (from a <> from b :: Rep a ())
mempty = to (mempty :: Rep a ())
fmap f = to1 . fmap f . from1
a <$ as = to1 (a <$ from1 as)
pure = to1 . pure
fs <*> as = to1 (from1 fs <*> from1 as)
liftA2 (·) as bs = to1 (liftA2 (·) (from1 as) (from1 bs))
empty = to1 empty
as1 <|> as2 = to1 (from1 as1 <|> from1 as2)