Home > Back-end >  Can I use DerivingVia to derive instances for data types isomorphic to tuples
Can I use DerivingVia to derive instances for data types isomorphic to tuples

Time:02-22

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.

CodePudding user response:

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)

CodePudding user response:

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

  • Related