Actually, there is a type class that would support this. It's not included in the standard type class but "representable functors" have this capability.
A representative functor is a functor F
with two things
- a type
A
- An isomorphism between
F
and(->) A
We could represent this as
type family ReprObj (f :: * -> *):: *
class Functor f => Repr f where
toHom :: f a -> (ReprObj f -> a)
fromHom :: (ReprObj f -> a) -> f a
where toHom . fromHom = fromHom . toHom = id
. An example of a representable functor,
newtype Pair a = Pair (a, a) deriving Functor
type instance ReprObj Pair = Bool
instance Repr Pair where
toHom (Pair (a, b)) True = a
toHom (Pair (a, b)) False = b
fromHom f = Pair (f True, f False)
Now using this we can derive
swap :: (Functor f, Functor g, Repr f, Repr g) => f (g a) -> g (f a)
swap g = fromHom $ \obj -> fmap ($ obj) hom
where hom = fmap toHom g
In fact, we can also get a free applicative and monad instance out of representable functors. I detailed how you could do this in a blog post.