– and prisms

A profunctor optic has the following general form

`type LensLike p s t a b = p a b -> p s t`

Compare this with the van Laarhoven version

`type LensLikeVL f s t a b = (a -> f b) -> s -> f t`

The 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'
```