Lenses, Folds, and Traversals
Pull request Compare This branch is 3546 commits behind ekmett:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Lens: Lenses, Folds, and Traversals

Build Status

This package provides families of lenses, isomorphisms, folds, traversals, getters and setters.

An overview of the derivation of these types can be found on the Lens Wiki along with a brief Tutorial.

Documentation is available through github or hackage.


You can read from lenses (or other getters) and they compose in the order an imperative programmer would expect.

ghci> :m + Control.Lens
ghci> ("hello",("world","!!!"))^._2._1

You can make getters out of pure functions with to.

ghci> ("hello",("world","!!!"))^._2._1.to length

You can write to lenses and these writes can change the type of the container.

ghci> _1 .~ "hello" $ ((),"world")

You can let the library automatically derive lenses for fields of your data type

import Control.Lens

data Foo a = Foo { _bar :: Int, _baz :: Int, _quux :: a }
makeLenses ''Foo

This will automatically generate the following lenses:

bar, baz :: Simple Lens (Foo a) Int
quux :: Lens (Foo a) (Foo b) a b

You can also write to setters that target multiple parts of a structure, or their composition with other lenses or setters.

ghci> _1.mapped._2.mapped %~ succ $ ([(42, "hello")],"world")
([(42, "ifmmp")],"world")
ghci> both *~ 2 $ (1,2)

There are combinators for manipulating the current state in a state monad as well

fresh :: MonadState Int m => m Int
fresh = id <+= 1

Anything you know how to do with a Foldable container, you can do with a Fold

ghci> :m + Data.Char Data.Text.Lens
ghci> allOf (folded.text) isLower ["hello"^.packed, "goodbye"^.packed]

You can also use this for generic programming:

ghci> :m + GHC.Generics.Lens
ghci> anyOf every (=="world") ("hello",(),[(2::Int,"world")])

Anything you know how to do with a Traversable you can do with a Traversal.

ghci> mapMOf (traverse._2) (\xs -> length xs <$ putStrLn xs) [(42,"hello"),(56,"world")]

Many of the lenses supplied are isomorphisms, that means you can use them directly as a lens:

ghci> let hello = "hello"^.packed
ghci> :t hello
hello :: Text

but you can also flip them around and use them as a lens the other way with from

ghci> hello^.from packed.to length

You can automatically derive isomorphisms for your own newtypes with makeIso. e.g.

newtype Neither a b = Neither { _nor :: Either a b } deriving (Show)
makeIso ''Neither

will automatically derive

neither :: Iso (Neither a b) (Neither c d) (Either a b) (Either c d)
nor :: Iso (Either a b) (Either c d) (Neither a b) (Neither c d)

such that

from neither = nor
from nor = neither
neither.nor = id
nor.neither = id

There is also a fully operational, but simple game of Pong in the examples/ folder.

Field Guide

Lens Hierarchy

Contact Information

Contributions and bug reports are welcome!

Please feel free to contact me through github or on the #haskell IRC channel on irc.freenode.net.

-Edward Kmett