Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the name of this prism-like optic, and is it useful for anything?

I'm currently working through tutorials for the Haskell lens package, so I can better understand the underlying mathematical foundations. And I was working through Prisms.

type Prism s t a b = forall p f. (Applicative f, Choice p) => p a (f b) -> p s (f t)

We find that a prism is effectively b -> t and s -> Either t a. We can exhibit this isomorphism directly.

-- Note: Stripping out the APrism / AReview type synonyms used
-- in Control.Lens for simplicity.

prism :: (b -> t) -> (s -> Either t a) -> Prism s t a b
prism bt seta = dimap seta (either pure (fmap bt)) . right'

matching :: Prism s t a b -> s -> Either t a
matching aprism s = let Market _ f = aprism (Market Identity Right) in
                    left runIdentity $ f s

review :: Prism s t a b -> b -> t
review areview = runIdentity . unTagged . areview . Tagged . Identity

(Note: Sources for Tagged and Market)

At this point, I had the thought "Hey, Choice is kind of just Strong but on Either rather than (,)". So I wanted to know what sort of prism-like thing you get if you replace Choice with Strong. I was expecting to write

type ProductPrism s t a b = forall p f. (Applicative f, Strong p) => p a (f b) -> p s (f t)

and find that ProductPrism s t a b is isomorphic to (b -> t, s -> (t, a)). But as I went to write these isomorphisms, I discovered two things:

  1. The b -> t part is actually irrelevant here (you don't need it in order to construct a ProductPrism)
  2. We don't need pure, so we can get by with Apply.

So I ended up with this.

type ProductPrism s t a b = forall p f. (Apply f, Strong p) => p a (f b) -> p s (f t)

-- Construct ProductPrism from (s -> (t, a))
productPrism :: (s -> (t, a)) -> ProductPrism s t a b
productPrism sta = dimap sta (\(t, fb) -> t <$ fb) . second'

-- Consume ProductPrism into (s -> (t, a))
split :: ProductPrism (Semi.First a) s t a -> s -> (t, a)
split pprism s = go $ pprism (\a -> (Semi.First a, a)) s
    where go (Semi.First a, t) = (t, a)

where Semi.First is the semigroup First (not the monoid version).

So ProductPrism s t a b, as I've defined it, is just s -> (t, a) with a comically unused b argument.

My question is: Is this type useful? Does this functional reference have a well-known name like Lens or Prism or Traversal? Does it give us any useful abstractions like many of the other optics do?

like image 353
Silvio Mayolo Avatar asked Oct 20 '25 11:10

Silvio Mayolo


1 Answers

I think you've gotten the choice of the c parameter in Strong wrong. It shouldn't be c ~ t; it should be c ~ s. So, my read is that you're looking for the following:

type PPrism s t a b = forall p f. (Functor f, Strong p) => p a (f b) -> p s (f t)

pprism :: (s -> a) -> (b -> s -> t) -> PPrism s t a b
pprism sa bst = dimap (\s -> (s, sa s)) (\(s, fb) -> flip bst s <$> fb) . second'

unprism :: PPrism s t a b -> ((s -> a), (b -> s -> t))
unprism pp = (sa, bst)
  where sa = getConst . pp (Const . id)
        bst b = runIdentity . pp (const (Identity b))

In short, this is really just a lens. (Or, if you choose Applicative f instead, a traversal.)

That makes sense, right? A Prism is an optical generalization of a sum type based on a profunctor with Choice. A Lens is an optical generalization of a product type based on a profunctor with Strong, though we usually just define it with p ~ (->).

like image 51
K. A. Buhr Avatar answered Oct 23 '25 06:10

K. A. Buhr



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!