Given the following data type
data Both a b = Both { left :: a, right :: b }
I can write instances for Applicative etc. like so (omitting Functor here as we can use DeriveFunctor
):
instance Monoid a => Applicative (Both a) where
pure x = Both mempty x
Both u f <*> Both v x = Both (u <> v) (f x)
Since Both
is isomorphic to (a,b)
, I'm wondering whether I can use DerivingVia
to derive the instance:
data Both a b = ... deriving Applicative via ((,) a)
which results in error messages like:
• Couldn't match representation of type ‘(a, a1)’
with that of ‘Both a a1’
arising from the coercion of the method ‘pure’
from type ‘forall a1. a1 -> (a, a1)’
to type ‘forall a1. a1 -> Both a a1’
• When deriving the instance for (Applicative (Both a))
which I interpret as "the compiler doesn't know how to turn Both
into (,)
". How do I tell the compiler to do that using the obvious way?
I've seen this question and the answers, but I'm hoping for a solution that requires less boilerplate.
Inspired by this answer, and with the help of the generic-data
package one can write:
{-# LANGUAGE DeriveGeneric, DerivingStrategies, DerivingVia #-}
import GHC.Generics
import Generic.Data
data Both a b = Both {left :: a, right :: b}
deriving stock (Generic1)
deriving (Functor, Applicative) via Generically1 (Both a)