Prism
also: prisms, affine traversal
The counterpart of a lens for sum types: a partial getter that succeeds only on one constructor, and a builder that makes a whole value from that constructor's contents. A lens composed with a prism has at most one focus and no builder, which is called an affine traversal.
A lens always finds its focus, because every record has every field. A variant value is one constructor out of several, so looking inside a particular constructor can fail, and the getter returns an option. In exchange, a prism can go backwards: the constructor contents are enough to build the whole value.
A prism as a record: preview matches, review builds.
type ('s, 'a) prism = { preview : 's -> 'a option; review : 'a -> 's }type shape = Circle of float | Rect of float * floatlet circle ={ preview = (function Circle r -> Some r | _ -> None);review = (fun r -> Circle r) }let over p f s = match p.preview s with Some a -> p.review (f a) | None -> s
Compiled with ocamlopt 5.5.1.
circle.preview (Circle 2.) -> Some 2circle.preview (Rect (1., 2.)) -> Nonecircle.review 3. -> Circle 3over circle (fun r -> r *. 2.) (Circle 2.) -> Circle 4over circle (fun r -> r *. 2.) (Rect (1., 2.)) -> Rect (1, 2)
The laws: preview (review a) = Some a, and if preview s = Some a then review a = s. The last line above is the useful property in practice: a modification through a prism that does not match leaves the value alone, so a deep edit into JSON or an AST is safe when the path does not exist.
see also
- LensA first-class pair of a getter and a setter for one part of a structure, with laws that make them agree: you get back what you set, setting what you got changes nothing, and a second set overwrites the first. Lenses compose, so a path through nested records is one value.
- Polymorphic variantA variant whose constructors, called tags and written with a backquote, exist independently of any type declaration. Their types are sets of tags with bounds: [> `A] means at least `A, [< `A | `B] at most those two, and unification works out unions and intersections of those sets.
referenced by
- lens in HaskellBuilding a lens from first principles, then the real library: Lens, Prism, Traversal, Iso, Fold, indexed optics, and generic derivation.
- Lenses and Prisms in OCamlAn optics library whose kinds are a phantom polymorphic variant, and a ppx that derives lenses from records, prisms from variants, and both from field paths and patterns.
further reading
- M. Pickering, J. Gibbons, N. Wu, “Profunctor optics: modular data accessors”, The Art, Science, and Engineering of Programming 1 (2017).