Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
This module provides linear optics.
Documentation for specific optics (lenses, prisms, traversals and isomorphisms) are provided in their respective modules.
Here we just provide an overview.
Some familiarity with optics is needed to understand linear optics. Please go through the (hopefully friendly!) background material section if you are unfamiliar with lenses, prisms, traversals or isomorphisms.
Background Material
If you don't know anything about optics, we suggest looking at the
resources below and playing with the lens
package.
- A great intro-to-lenses talk by Simon Peyton Jones
- A nice introductory blog post
- A friendly introduction to prisms and isos
- The wiki of the
lens
package that contains some nice examples
Conceptualizing and using optics
What are linear optics?
Optics can be conceptualized as a first class object with which you can view and map functions over sub-structure(s) within a larger structure.
Linear optics are optics where the "viewing" and "mapping" are done with linear functions (and any corresponding structures hold values linearly, i.e., with constructors that use linear arrows).
In types: a (linear) optic of type Optic s t a b
is a way of viewing the
sub-structure(s) of type a
in the structure of type s
and mapping a
function from an a
to a b
on those sub-structures in s
which change an
s
to a t
. The non-polymorphic version of the optic is specialized
to the types Optic s s a a
and is usually defined with a tick mark,
e.g., the non-polymorphic Lens
is Lens'
.
There are four basic optics: traversals, lenses, prisms and isomorphisms.
Sub-typing diagram of optics
\[ \texttt{Traversal} \] \[ \Huge \nearrow ~~~~~ \nwarrow \] \[ \texttt{Lens}\hspace{6em}\texttt{Prism} \] \[ \Huge \nwarrow ~~~~~ \nearrow \] \[ \texttt{Iso} \]
In the diagram above, the arrows X --> Y
mean any of the following
equivalent things:
- X is a specialization of Y
- X is a strict subset of Y
- You can (basically) implement
f :: X -> Y
withf = id
but you can't implementf :: Y -> X
.
A bird's eye view of the types
The types of linear optics are generalizations of the standard optic
types from the lens
package.
These are the standard optic types:
type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t type Lens s t a b = forall f. Functor f => (a -> f b) -> (s -> f t) type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t) type Iso s t a b = forall p f. (Profunctor p, Functor f) => a `p` (f b) -> s `p` (f t)
These are (basically) the linear optic types:
type Traversal a b s t = forall arr. Wandering arr => (a `arr` b) -> (s `arr` t) type Lens a b s t = forall arr. Strong (,) () arr => (a `arr` b) -> (s `arr` t) type Prism a b s t = forall arr. Strong Either Void arr => (a `arr` b) -> (s `arr` t) type Iso a b s t = forall arr. Profunctor arr => (a `arr` b) -> (s `arr` t)
Below is a table that lists the instances of the typeclasses which generalize the standard optics.
Note that Kleisli arrows basically defined like so:
type Kleisli f a b = a #-> f b
Note: We abbreviate Control for Control.Functor.Linear.
Profunctor | Strong (,) () | Strong Either Void | Wandering | |
---|---|---|---|---|
(->) | X | X | X | |
(#->) | X | X | X | |
(Prelude)
Functor f
=> Kleisli f | X (4) | X | ||
(Data.Functor)
Functor f
=> Kleisli f | X | |||
(Prelude)
Applicative f
=> Kleisli f | X | X | X (3) | |
(Control)
Functor f
=> Kleisli f | X | X (2) | ||
(Control)
Applicative f
=> Kleisli f | X | X | X | X (1) |
Essentially:
- The instance marked (1) implies that the linear traversal definition includes the standard one
- The instance marked by (2) implies that the linear lens definition includes the standard one
- The instance marked by (3) implies that the linear prism definition includes the standard one
- The instance marked by (4) implies that the linear iso definition includes the standard one
Documentation
module Control.Optics.Linear.Iso
module Control.Optics.Linear.Lens
module Control.Optics.Linear.Prism