theorem definition example program

Profunctor optics represent an optic (lens, prism, traversal, iso, …) as a function polymorphic over a class of profunctors; composition of optics is then ordinary function composition — like representing rotations by matrices so that composing them is matrix multiplication. The master formula, from Tannakian Reconstruction over a free/forgetful adjunction between a category of structured profunctors and all profunctors, with :

Sources: DaoFP §18.2 (“Profunctor Lenses”: “Iso”, “Profunctor lenses”, “Profunctor lenses in Haskell”), §18.3 (“General Optics”: “Prisms”, “Traversals”), §18.4 (“Mixed Optics”), Exercises 18.2.1, 18.4.1; §17.9 (Existential Lens).

opticexistential / concrete formprofunctor form
Iso (adapter)all profunctors: (s -> a, b -> t)forall p. Profunctor p => p a b -> p s t
LensTambara for (Cartesian); get, setforall p. Cartesian p => p a b -> p s t
PrismTambara for (Cocartesian); match :: s -> Either t a, build :: b -> tforall p. Cocartesian p => p a b -> p s t
Traversalgeneralized Tambara for ; s -> ([b] -> t, [a]) (sizes must match — really needs dependent types)forall p. Traversing p => p a b -> p s t
  • Iso: toIsoP (f, g) = dimap f g; conversely a function that maps for every profunctor can only be a closure over a pair (s -> a, b -> t) — recovered by feeding the profunctor Adapter a b s t = (s -> a, b -> t) at the identities (DaoFP Exercise 18.2.1).
  • Lens: toLensP (LensE from to) = dimap from to . alpha; back via the Cartesian profunctor FlipLens a b s t = (s -> a, s -> b -> t) fed with FlipLens id (\_ b -> b). Composition: lens3 = lens2 . lens1.
  • Prism: s either contains the focus a or a residue c; mapping out of a sum turns the coend into by co-Yoneda. toPrismP (Prism from to) = dimap from to . alpha'.
  • Traversal: residues with holes form a functor ; the actions compose by Day Convolution on , and the general Tambara derivation goes through unchanged. Mixed optics use an actegory acting on two categories.

The general notion — mixed optics for arbitrary actions — is Optic.

Docs: plain Julia — Catlab has no dedicated API for this; related: Catlab v0.16 docs · GATlab standard library

# profunctor lens on the function profunctor: p a b -> p s t with p = (->), i.e. an "over"
alpha(f) = ((c, a),) -> (c, f(a))
dimap(l, r, h) = r ∘ h ∘ l
# LensE (c, a) (c, b) a b for the second component of a pair, as a profunctor lens
lensP(h) = dimap(identity, identity, alpha(h))
over_second = lensP(x -> x * 10)
over_second(("tag", 4))                # ("tag", 40)
# lenses compose by function composition
over_inner = lensP(lensP(x -> x + 1))
over_inner(("a", ("b", 1)))            # ("a", ("b", 2))
import Mathlib
-- the profunctor representation instantiated at p := (· → ·) gives "modify the focus"
def overSnd (h : α → β) : γ × α → γ × β := fun ⟨c, a⟩ => (c, h a)
example : overSnd (· * 10) ("tag", 4) = ("tag", 40) := rfl
{-# LANGUAGE RankNTypes, GADTs #-}
type IsoP s t a b = forall p. Profunctor p => p a b -> p s t
toIsoP :: (s -> a, b -> t) -> IsoP s t a b
toIsoP (f, g) = dimap f g
 
type LensP s t a b = forall p. Cartesian p => p a b -> p s t
toLensP :: LensE s t a b -> LensP s t a b
toLensP (LensE from to) = dimap from to . alpha
 
data FlipLens a b s t = FlipLens (s -> a) (s -> b -> t)
instance Profunctor (FlipLens a b) where
  dimap f g (FlipLens get set) = FlipLens (get . f) (fmap g . set . f)
instance Cartesian (FlipLens a b) where
  alpha (FlipLens get set) = FlipLens (get . snd) (\(x, s) b -> (x, set s b))
fromLensP :: LensP s t a b -> (s -> a, s -> b -> t)
fromLensP pp = (get', set') where FlipLens get' set' = pp (FlipLens id (\_ b -> b))
 
data Prism s t a b where
  Prism :: (s -> Either c a) -> (Either c b -> t) -> Prism s t a b
toMatch :: Prism s t a b -> (s -> Either t a)
toMatch (Prism from to) s = case from s of
  Left c  -> Left (to (Left c))
  Right a -> Right a
toBuild :: Prism s t a b -> (b -> t)
toBuild (Prism _ to) b = to (Right b)
type PrismP s t a b = forall p. Cocartesian p => p a b -> p s t
toPrismP :: Prism s t a b -> PrismP s t a b
toPrismP (Prism from to) = dimap from to . alpha'