Can I use DerivingVia to derive instances for data types isomorphic to tuples

243 Views Asked by At

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.

2

There are 2 best solutions below

0
l7r7 On BEST ANSWER

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)
0
Georgi Lyubenov On

The DerivingVia paper has a section on using Generic to derive arbitrary classes for things that are "isomorphic via Generic". See 4.3.

I feel like I've seen the approach adapted to a library on hackage, but I can't seem to find it now.

However, I'm not sure it would work for your case, as (a, b) and your type might not have the same Generic representation (your type has record fields). "data type generic surgery" could also be useful in that case - https://github.com/Lysxia/generic-data-surgery#readme