functional optics

utility
Consider one data structure which holds, nests
, another:
data A = { b : B }
data B = { x : Number }
a = A (B 1)
A (B x) = a
x = 1
.
While terse, functions written across this nesting become increasingly unweildy:
shiftA : A -> A
shiftA (A (B x)) = A (B (x + 1))
shiftA
's meaning.
shiftA : A -> A
shiftA = over (b . x) (+ 1)
over
(think: over-write) is a function focusing the
b
's x
, allowing the more direct expression of the intended meaning.
(More broadly, this is point-free.)
The b and x, used for this focusing, are the lenses of functional optics.
Lenses
Lens
, at its simplist, can be expressed as the pair view
and over
:
data Lens s a =
{ view : s -> a
, over : (a -> a) -> (s -> s)
}
Lens s a
can be read as focusing, wherea
froms
a
is some smaller nested part of the larger s
.
view
will get from s
the focus,
over
is slightly more invovled:
it uses an update to the focus, a -> a
, yeilding a change to an s
.
Consider the simpler case of over
that doesn't update the focus, just sets it to a new value:
set : a -> (s -> s)
over
with a -> a
being constant, ignoring the prior value of the focus:
set a s = over (const a) s
encodings
Lens
can be re-expressed in multiple forms:
type Lens s a
= forall f. Functor f
=> (a -> f a) -> s -> f s
view
and over
are implicit,
requiring the properties of Functor
to be understood (see Appendix.)
The expression using only functions does, however, allow for the more obvious use of composition.
composition
Lenses, by themselves, are not particularly expressive; their utility comes from the ease of their composition.
Two lenses, Lens a b
and Lens b c
combine for a Lens a c
;
in function encodings like Van Laarhoven's,
this composition is standard the composition of functions (.)
:
(.) : Functor f
=> ((b -> f b) -> (a -> f a))
-> ((c -> f c) -> (b -> f b))
-> ((c -> f c) -> (a -> f a))
view
and over
to form the distributivity laws of lenses:
view (lens1 . lens2) = (view lens2) . (view lens1)
over (lens1 . lens2) = (over lens1) . (over lens2)
view id = id
over id = id
further
- Traversals
- Prisms
lab
register files with lenses
references
usage
Example lifted from Control.Lens.Tutorial. (wayback)- optic (in computer science) (nLab)
- Optics for the Working Mathematician (Milewski)
- lens (in computer science) (nLab)
- Aaron Bohannon
- Existential Optics. Tweag blog.
appendix
Van Laarhoven encoding
type Lens = forall f. Functor f => (a -> f a) -> (s -> f s)
view
and over
,
which are recovered by application of specific f
.
For f = Identity
,
: (a -> Identity a) -> (s -> Identity s)
over : (a -> a) -> (s -> s)
over
is restored;
similarly, for f = Const a
, applied with id : a -> a
:
: ((a -> Const a a) -> (s -> Const a s)) (a -> a)
: ((a -> a) -> (s -> a)) (a -> a)
view : s -> a
view
is restored.