Reputation: 78
I'm fiddling with profunctor optics and I've some up against something I can't quite figure out.
The profunctor encoding of Lens and its inversion is as follows:
type Optic p s t a b = p a b -> p s t
type Lens s t a b = forall p. Strong p => Optic p s t a b
type LensyReview t b = forall p. Costrong p => Optic p t t b b
you can freely convert between them back and forth using
newtype Re p s t a b = Re { unRe :: p b a -> p t s }
instance Profunctor p => Profunctor (Re p s t) where
dimap f g (Re p) = Re (p . dimap g f)
instance Strong p => Costrong (Re p s t) where
unfirst (Re p) = Re (p . first')
unsecond (Re p) = Re (p . second')
instance Costrong p => Strong (Re p s t) where
first' (Re p) = Re (p . unfirst)
second' (Re p) = Re (p . unsecond)
re :: Optic (Re p a b) s t a b -> Optic p b a t s
re optic = unRe (optic (Re id)))
Now, I tried to implement choosing function (https://hackage.haskell.org/package/lens-4.17/docs/Control-Lens-Lens.html#v:choosing) for a profunctor lens.
It turns out that this requires additional type class:
class Profunctor p => SumProfunctor p where
(+++!) :: p a b -> p a' b' -> p (Either a a') (Either b b')
then if we include SumProfunctor in Lens, we can write
choosing :: Lens s t a b -> Lens s' t' a b -> Lens (Either s s') (Either t t') a b
choosing optic optic' = \pab -> optic pab +++! optic' pab
but then there needs to be another "dual" type class that follows the pattern for Re such that
instance Unknown p => ProfunctorSum (Re p s t)
instance ProfunctorSum p => Unknown (Re p s t)
so that Lens is reversible.
The closest I came up with was:
class Profunctor p => Unknown p where
unsum :: p (Either a a') (Either b b') -> (p a b -> r) -> (p a' b' -> r) -> r
as there is a sensible instance for Tagged of it and then you can write
instance Unknown p => SumProfunctor (Re p s t) where
Re f +++! Re g = Re (\s -> unsum s f g)
but defining it in the other direction, i.e.
instance SumProfunctor p => Unknown (Re p s t) where
unsum = ???
doesn't seem possible.
Am on on the right track or some other method is needed?
Upvotes: 1
Views: 187
Reputation: 3081
SumProfunctor
is equivalent to Choice, with p +++ q = left p . right q
Cochoice is the dual class:
instance Cochoice p => Choice (Re p s t) where
left' (Re f) = Re (f . unleft)
right' (Re f) = Re (f . unright)
instance Choice p => Cochoice (Re p s t) where
unleft (Re f) = Re (f . left')
unright (Re f) = Re (f . right')
Upvotes: 1