– and prisms
A profunctor optic has the following general form
type LensLike p s t a b = p a b -> p s tCompare this with the van Laarhoven version
type LensLikeVL f s t a b = (a -> f b) -> s -> f tThe way we write lenses in profunctor form is to see p a b as some
sort of converter from a to b and transform it to a converter from
s to t. Lenses work with the profunctor typeclass Strong,
defined by the following method:
first' :: p a b -> p (a, c) (b, c)That allows a converter from a to b to be transformed into a
converter from “a and some stuff” “b and some stuff”, that is any
product containing an a that can be “converted to” a b! That means
we can write a lens (in terms of second' rather than first' since
it makes the sequel slightly more convenient) by splitting s into
“a and some stuff” and feeding it into one end of the Strong
profunctor. Then we assemble t on the other end from “b and some
stuff”.
_1 :: Strong p => p a a' -> p (a, b, c) (a', b, c)
_1 = dimap (\(a, b, c) -> ((b, c), a)) (\((b, c), a) -> (a, b, c)) . second'In fact there are different representations for “stuff”. The stuff could even have been the assembling function itself:
_1' :: Strong p => p a a' -> p (a, b, c) (a', b, c)
_1' = dimap (\(a, b, c) -> (\a' -> (a', b, c), a)) (\(b_c, a) -> b_c a) . second'This suggests the following, which turns out to be a way of creating a profunctor lens from a getter/setter:
lens :: Strong p => (s -> (b -> t, a)) -> p a b -> p s t
lens f = dimap f (uncurry ($)) . second'Prisms work with the profunctor typeclass Choice, defined by the
following method:
left' :: p a b -> p (Either a c) (Either b c)This time we don’t use “a and some stuff” but instead “a or some
stuff”.
_Just :: Choice p => p a a' -> p (Maybe a) (Maybe a')
_Just = dimap (\case {Nothing -> Right (); Just a -> Left a})
(\case {Left a' -> Just a'; Right () -> Nothing})
. left'As before there’s an equivalent way of presenting this
_Just' :: Choice p => p a a' -> p (Either a t) ((a' -> t) -> t)
_Just' = rmap (\case {Left a' -> ($ a'); Right t -> const t})
. left'which leads to a way of creating a prism from a match and constructor.
prism :: Choice p
=> (s -> Either a t) -> (b -> t) -> p a b -> p s t
prism f g = dimap f (\case {Left a' -> g a'; Right t -> t}) . left'