Is there a van Laarhoven representation of `Optional`
Asked Answered
L

1

16

Many types of optics have a van Laarhoven representation.

For example, a Lens of type Lens s t a b can be represented as:

 Functor f => (a -> f b) -> s -> f t

Similarly a Traversal, can be represented in a similar way, swapping the Functor constraint for Applicative:

 Applicative f => (a -> f b) -> s -> f t

Several optics frameworks, such as Monocle and Arrow define a type called Optional.

In Monocle's Optics heirarchy Optional fits between Lens and Traversal

As I understand it: If a Traversal is like a Lens that may have zero to many targets, then an Optional is like a Lens that may have zero to one targets.

In Monocle, Optional is defined as a pair of functions:

getOrModify :: s -> Either t a 
set :: (b, s) -> t

Comments in the Monocle source code suggest that it's also possible to represent an Optional "as a weaker PLens and weaker PPrism"

Is it possible to represent an Optional as a van Laarhoven function?

Larimer answered 27/10, 2019 at 21:19 Comment(0)
C
10

There would be a way to represent it if the Functor/Applicative/Monad hierarchy were more fine-grained. In particular:

class Functor f => Pointed f where
    pure :: a -> f a

type Optional s t a b = forall f. Pointed f => (a -> f b) -> s -> f t

Note that the type would probably be named Affine in the lens library if that was neatly in the class hierarchy.

Cubbyhole answered 27/10, 2019 at 21:59 Comment(7)
This is conveniently completely fine for my use case, which is a "just for fun" Scala Optics Library where I've written the Functor Hierarchy from scratch, and can therefore do whatever I like with it. Am I right in thinking that this suggests that If I also had a another type-class between Functor and Applicative with liftA2, but no pure, then that would define an optic with one to many targets? Does this have a name?Larimer
It does suggest that. I have no idea what the optic would be called.Cubbyhole
@Larimer That intermediate class is called Apply in the "semigroupoids" package. hackage.haskell.org/package/semigroupoids-5.3.3/docs/…Wadleigh
... and the corresponding optic in the lens package is called Traversal1Pennington
@Cubbyhole How can we verify that this type Optional s t a b is indeed the correct representation for that optic, and that all the appropriate laws hold? This seems like a magical trick. Why was it Pointed and not, say, Copointed? For another given optic, how can we guess the correct profunctor representation?Bilek
@Bilek If you write a bunch of van Laarhoven lenses and traversals by hand (very highly recommended - they're not magic), you eventually get a handle on how the operations correspond to the number of targets present in a data structure. fmap handles a structure with a single target. pure handles a structure with no targets. (<*>) combines substructures that have each handled targets. From this you can observe that something with only fmap and pure will let you handle 0 or 1 targets, but not more than 1. And that's Pointed.Cubbyhole
As for Profunctor optics... Dunno. I've never really seen the appeal, so I haven't written enough of them by hand to see what the blocks are. My impression from the little I have done is that they don't seem as amenable to piecewise breakdowns. (That impression may be wrong.)Cubbyhole

© 2022 - 2024 — McMap. All rights reserved.