Coercing when Rep only equal after deeply evaluating type representations

I want to learn to use Deriving Via for more types. Currently a problem I'm often struggling with is when the generic representations are different, but would be equal if the conversion to type representations went deeper into nested types.

Simple example:

coerce @(Either () ()) @Bool

doesn't work, as Rec0 () :+: Rec0 () doesn't coerce with U1 :+: U1, even though :kind! Rep () gives U1, too.

More complex example

data LeafTree a = Leaf a | Branch [LeafTree a]

is isomorphic to Free [] a and it doesn't coerce for similar reasons. How I can I coerce between these types? I also know how to use DerivingVia with coercing between types with equal Rep1 if that helps here.


  • Now with the iso-deriving package a monad instance could also be derived like this:

    {-# LANGUAGE TypeOperators, FlexibleInstances, MultiParamTypeClasses, DeriveTraversable, DerivingVia #-}
    import Control.Monad.Free
    import Iso.Deriving
    data LeafTree a = Leaf a | Branch [LeafTree a]
      deriving (Functor)
      deriving (Applicative, Monad) via Free [] `As1` LeafTree
    instance Inject (Free [] a) (LeafTree a) where
      inj (Pure x ) = Leaf x
      inj (Free xs) = Branch (fmap inj xs)
    instance Project (Free [] a) (LeafTree a) where
      prj (Leaf   x ) = Pure x
      prj (Branch xs) = Free (fmap prj xs)
    instance Isomorphic (Free [] a) (LeafTree a)