Hi @Matthew, here's my take on the puzzle:

I've created two classes, one for each preservation property

class PreservesCoproduct f where

extractCoproduct :: f (Either a b) -> Either (f a) (f b)

introduceCoproduct :: Either (f a) (f b) -> f (Either a b)

class PreservesProduct f where

extractProduct :: f (a, b) -> (f a, f b)

introduceProduct :: (f a, f b) -> f (a, b)

And then two implementations: (I've needed to add the extentions FlexibleInstances and UndecidableInstances)

instance Adjunction f g => PreservesCoproduct f where

extractCoproduct = rightAdjunct $ fmap Left . unit ||| fmap Right . unit

introduceCoproduct = fmap Left ||| fmap Right

instance Adjunction f g => PreservesProduct g where

extractProduct = fmap fst &&& fmap snd

introduceProduct = leftAdjunct $ counit . fmap fst &&& counit . fmap snd

Both `introduceCoproduct` and `extractProduct` only need `f`(or `g`) to be functors, so they can be put into another instance with a less strong condition.

Function `introduceProduct` is the uncurried version of `f a -> f b -> f (a, b)` which can be found in the

[monoidal presentation](https://en.wikibooks.org/wiki/Haskell/Applicative_functors#The_monoidal_presentation) for **applicative functors**.

The last one, `extractCoproduct`, I cannot relate with anything I know (besides being the dual of the "monoidal" one).

And that's all (for now ;-D)

I've created two classes, one for each preservation property

class PreservesCoproduct f where

extractCoproduct :: f (Either a b) -> Either (f a) (f b)

introduceCoproduct :: Either (f a) (f b) -> f (Either a b)

class PreservesProduct f where

extractProduct :: f (a, b) -> (f a, f b)

introduceProduct :: (f a, f b) -> f (a, b)

And then two implementations: (I've needed to add the extentions FlexibleInstances and UndecidableInstances)

instance Adjunction f g => PreservesCoproduct f where

extractCoproduct = rightAdjunct $ fmap Left . unit ||| fmap Right . unit

introduceCoproduct = fmap Left ||| fmap Right

instance Adjunction f g => PreservesProduct g where

extractProduct = fmap fst &&& fmap snd

introduceProduct = leftAdjunct $ counit . fmap fst &&& counit . fmap snd

Both `introduceCoproduct` and `extractProduct` only need `f`(or `g`) to be functors, so they can be put into another instance with a less strong condition.

Function `introduceProduct` is the uncurried version of `f a -> f b -> f (a, b)` which can be found in the

[monoidal presentation](https://en.wikibooks.org/wiki/Haskell/Applicative_functors#The_monoidal_presentation) for **applicative functors**.

The last one, `extractCoproduct`, I cannot relate with anything I know (besides being the dual of the "monoidal" one).

And that's all (for now ;-D)