Lenses, Folds and Traversals
This package comes "Batteries Included" with many useful lenses for
the types commonly used from the Haskell Platform, and with tools for
automatically generating lenses and isomorphisms for user-supplied
data types.
The combinators in
Control.Lens provide a highly generic
toolbox for composing families of getters, folds, isomorphisms,
traversals, setters and lenses and their indexed variants.
An overview, with a large number of examples can be found in the
README.
An introductory video on the style of code used in this library by
Simon Peyton Jones is available from
Skills Matter.
A video on how to use lenses and how they are constructed is available
on
youtube.
Slides for that second talk can be obtained from
comonad.com.
More information on the care and feeding of lenses, including a brief
tutorial and motivation for their types can be found on the
lens
wiki.
A small game of
pong and other more complex examples that
manage their state using lenses can be found in the
example
folder.
Lenses, Folds and Traversals
With some signatures simplified, the core of the hierarchy of
lens-like constructions looks like:
(Local Copy)
You can compose any two elements of the hierarchy above using
(.) from the
Prelude, and you can use any element of
the hierarchy as any type it linked to above it.
The result is their lowest upper bound in the hierarchy (or an error
if that bound doesn't exist).
For instance:
Minimizing Dependencies
If you want to provide lenses and traversals for your own types in
your own libraries, then you can do so without incurring a dependency
on this (or any other) lens package at all.
e.g. for a data type:
data Foo a = Foo Int Int a
You can define lenses such as
-- bar :: Lens' (Foo a) Int
bar :: Functor f => (Int -> f Int) -> Foo a -> f (Foo a)
bar f (Foo a b c) = fmap (\a' -> Foo a' b c) (f a)
-- quux :: Lens (Foo a) (Foo b) a b
quux :: Functor f => (a -> f b) -> Foo a -> f (Foo b)
quux f (Foo a b c) = fmap (Foo a b) (f c)
without the need to use any type that isn't already defined in the
Prelude.
And you can define a traversal of multiple fields with
Control.Applicative.Applicative:
-- traverseBarAndBaz :: Traversal' (Foo a) Int
traverseBarAndBaz :: Applicative f => (Int -> f Int) -> Foo a -> f (Foo a)
traverseBarAndBaz f (Foo a b c) = Foo <$> f a <*> f b <*> pure c
What is provided in this library is a number of stock lenses and
traversals for common haskell types, a wide array of combinators for
working them, and more exotic functionality, (
e.g. getters,
setters, indexed folds, isomorphisms).