Which functors are "strong with respect to Either"?
I'm reading the Profunctor Optics paper and in it they implement an instance of Strong (they call it Cartesian) for the Star (aka UpStar) of a functor, like so:
instance Functor f => Cartesian (UpStar f) where
first (UpStar u) = UpStar (rstrength . cross u id)
second (UpStar u) = UpStar (lstrength . cross id u)
-- some givens:
newtype UpStar f a b = UpStar {unUpStar :: a -> f b}
newtype Costar f a b = Costar {unCostar :: f a -> b}
instance Functor f => Profunctor (UpStar f) where
dimap f g (UpStar h) = UpStar (fmap g . h . f)
rstrength :: Functor f => (f a, b) -> f (a, b)
rstrength (fx, y) = fmap (,y) fx
lstrength :: Functor f => (a, f b) -> f (a, b)
lstrength (x, fy) = fmap (x,) fy
cross :: (t1 -> a) -> (t2 -> b) -> (t1, t2) -> (a, b)
cross f g (a,b) = (f a, g b)
The paper doesn't go into the dual of Star much (profunctors calls it Costar,) however, the docs for profunctors say in passing that Choice, aka Cocartesian, is "The generalization of Costar of Functor that is strong with respect to Either."
Which means one could do something like this:
instance Functor f => Choice (Costar f) where
left (Costar c) = Costar magicL
right (Costar c) = Costar magicR
magicR :: f (Either c a) -> Either c b
magicR = error "questionable"
magicL :: f (Either a c) -> Either b c
magicL = error "also questionable"
But surely those magic functions are too coarse/not applicable to all functors, since I can't figure out how to implement them for a general f!
My question is... I can't quite think of examples of functors for which one can write instance Choice (Costar f), or even come up with a composition of parts like they approached it for Strong + Star. There used to be a "highly questionable" instance for Traversable in profunctors -- I don't quite get why it was highly questionable, maybe it didn't uphold the profunctor/choice laws?
Interestingly, both the paper and profunctors define the instance Applicative f => instance Choice (Star f), because it's possible to "put" something into f via pure in Applicative, but not in a more general Functor; so maybe the Costar route works for stuff where one can "take" something out of a functor? (That is probably wrong: there's surely a reason why the Choice instance for Comonad doesn't go this route!)
Anyhoo, I'm sure there's some really evident things I'm not seeing here, curious to see what the intuition is for which functors qualify for "strong with respect Either" to someone out there better at the more categorical theoretic side of Haskell!
Posted Dec 12, 2021, 12:49 AM UTC · edited
This quote from documentation Data.Profunctor.Choice might be the issue.
I guess "The generalization of Costar of Functor that is costrong with respect to Either." was the intention
behind them.A Functor
fis strong w.r.t.Eithermeans it hasfis costrong w.r.t.Eithermeanswhere each has to obey associativity law. In fact
The last isomorphism is by Yoneda
(∀b. (f a -> b) -> Either b c) ~ Yoneda (Either _ c) (f a) ~ Either (f a) c.I'm not sure there's a well known subclass of
Functorwhich hascostrengthE, but I can imagine a subclass ofTraversable twithwhich implies (if I'm not missing some detail) a lawful
costrengthEusing the "highly questionable" instance in the linked history.