lens
Version 1.1.1 revision 1 uploaded by EdwardKmett.
Package meta
- Synopsis
- Families of Lenses, Folds and Traversals
- Description
The combinators in
Control.Lens
provide a highly generic toolbox for composing families of getters, folds, traversals, setters and lenses.Getter
A
Getter a b c d
is just any function(a -> c)
, which we've flipped into continuation passing style,forall r. (c -> r) -> a -> r
and decorated with Const to obtaintype Getter a b c d = forall r. (c -> Const r d) -> a -> Const r b
Everything you can do with a function, you can do with a Getter, but note that because of the continuation passing style (.) composes them in the opposite order.
Since it is only a function, every Getter obviously only retrieves a single value for a given input.
Fold
A
Fold a b c d
is a generalization of something Foldable. It allows you to extract multiple results from a container. A Foldable container can be characterized by the behavior offoldMap :: (Foldable t, Monoid m) => (c -> m) -> t c -> m
. Since we want to be able to work with monomorphic containers, we generalize this signature toforall m. Monoid m => (c -> m) -> a -> m
, and then decorate it with Const to obtaintype Fold a b c d = forall m. Monoid m => (c -> Const m d) -> a -> Const m b
Every Getter is a valid Fold that simply doesn't use the Monoid it is passed.
Everything you can do with a Foldable container, you can with with a Fold and there are combinators that generalize the usual Foldable operations in
Control.Lens
.Traversal
A
Traversal a b c d
is a generalization of traverse from Traversable. It allows you to traverse over a structure and change out its contents with monadic or applicative side-effects. Starting fromtraverse :: (Traversable t, Applicative f) => (c -> f d) -> t c -> f (t d)
, we monomorphize the contents and result to obtaintype Traversal a b c d = forall f. Applicative f => (c -> f d) -> a -> f b
Every Traversal can be used as a valid Fold, because given a Monoid
m
, we have an Applicative for(Const m)
. Everything you can do with a Traversable container, you can with with a Traversal, and there are combinators that generalize the usual Traversable operations inControl.Lens
.Setter
A
Setter a b c d
is a generalization of fmap from Functor. It allows you to map into a structure and change out the contents, but it isn't strong enough to allow you to enumerate those contents. Starting withfmap :: Functor f => (c -> d) -> f c -> f d
we monomorphize the type to obtain(c -> d) -> a -> b
and then decorate it with Identity to obtaintype Setter a b c d = (c -> Identity d) -> a -> Identity b
Every Traversal is a valid Setter, since Identity is Applicative.
Everything you can do with a Functor, you can do with a Setter, and there are combinators that generalize the usual Functor operations in
Control.Lens
.Lens
A
Lens a b c d
is a purely functional reference.While a Traversal was a valid Fold, it wasn't a valid Getter. To make the Applicative for Const it required a Monoid for the argument we passed it, which a Getter doesn't recieve.
However, the instance of Functor for Const requires no such thing. If we weaken the type requirement from Applicative to Functor for Traversal, we obtain
type Lens a b c d = forall f. Functor f => (c -> f d) -> a -> f b
Every Lens is a valid Setter, choosing
f
= Identity.Every Lens is a valid Fold that doesn't use the Monoid it is passed.
Every Lens is a valid Traversal that only uses the Functor part of the Applicative it is supplied.
Every Lens is a valid Getter, choosing
f
= Constr
for an appropriater
Since every Lens is a valid Getter it follows that it must view exactly one element in the structure.
The lens laws follow from this property and the desire for it to act like a Functor when used as a Setter.
Composition
Note that all of these types are type aliases, and you can compose these lenses with mere function compositon.
This is a generalization of the well-known trick for
(.).(.)
orfmap.fmap
, and their less well-known cousinsfoldMap.foldMap
traverse.traverse
. It follows because each one is a function between values of type(x -> f y)
and the composition takes the intersection of supplied functionality for you automatically!Lens Families
For a longer description of why you should care about lenses, and an overview of why we use 4 parameters a, b, c, and d instead of just 2, see http://comonad.com/reader/2012/mirrored-lenses/.
Sometimes you won't need the flexibility those extra parameters afford you and you can use
type Simple f a b = f a a b b
to describe a Simple Lens, Simple Traversal or Simple Setter.
Avoiding Dependencies
Note: If you merely want your library to provide lenses you may not have to actually import any lens library at all. For, say, a
Simple Lens Bar Foo
, just export a function with the signature:foo :: Functor f => (Foo -> f Foo) -> Bar -> f Bar
and then you can compose it with other lenses using nothing more than
(.)
from the Prelude.Deriving Lenses
You can derive lenses automatically for many data types using Control.Lens.TH, and if a container is fully characterized by its lenses, you can use Control.Lens.Representable to automatically derive Functor, Applicative, Monad, and Derivable.
- Author
- Edward A. Kmett
- Bug reports
- http://github.com/ekmett/lens/issues
- Category
- Data, Lenses
- Copyright
- Copyright (C) 2012 Edward A. Kmett
- Homepage
- http://github.com/ekmett/lens/
- Maintainer
- Edward A. Kmett <ekmett@gmail.com>
- Package URL
- n/a
- Stability
- provisional