Skip to content
This repository

Lenses, Folds, and Traversals - Join us on freenode #haskell-lens

README.markdown

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.

Plated

New in version 2.5 is a port of the Uniplate API, updated to use Traversal. The Data-derived biplate and uniplate combinators run about 25% faster than the original uniplate, and you can use any of the other combinators, since biplate and uniplate are now just traversals.

Examples

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
"world"

You can make getters out of pure functions with to.

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

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

ghci> _1 .~ "hello" $ ((),"world")
("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)
(2,4)

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]
True

You can also use this for generic programming:

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

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")]
"hello"
"world"
[(42,5),(56,5)]

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

ghci> let hello = "hello"^.packed
"hello"
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
5

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

Something went wrong with that request. Please try again.