Readme for lens-3.7.1
Lens: Lenses, Folds, and Traversals
This package provides families of lenses, isomorphisms, folds, traversals, getters and setters.
The FAQ, which provides links to a large number of different resources for learning about lenses and an overview of the derivation of these types can be found on the Lens Wiki along with a brief overview and some examples.
Documentation is available through github (for HEAD) or hackage for the current and preceding releases.
Field Guide
Examples
(See wiki/Examples
)
First, import Control.Lens
.
ghci> import Control.Lens
Now, you can read from lenses
ghci> ("hello","world")^._2
"world"
and you can write to lenses.
ghci> set _2 42 ("hello","world")
("hello",42)
Composing lenses for reading (or writing) goes in the order an imperative programmer would expect, and just uses (.)
from the Prelude
.
ghci> ("hello",("world","!!!"))^._2._1
"world"
ghci> set (_2._1) 42 ("hello",("world","!!!"))
("hello",(42,"!!!"))
You can make a Getter
out of a pure functions with to
.
ghci> "hello"^.to length
5
You can easily compose a Getter
with a Lens
just using (.)
. No explicit coercion is necessary.
ghci> ("hello",("world","!!!"))^._2._2.to length
3
As we saw above, you can write to lenses and these writes can change the type of the container. (.~)
is an infix alias for set
.
ghci> _1 .~ "hello" $ ((),"world")
("hello","world)
Conversely view
, can be used as a prefix alias for (^.)
.
ghci> view _2 (10,20)
20
There are a large number of other lens variants provided by the library, in particular a Traversal
generalizes traverse
from Data.Traversable
.
We'll come back to those later, but continuing with just lenses:
You can let the library automatically derive lenses for fields of your data type
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
A Lens
takes 4 parameters because it can change the types of the whole when you change the type of the part.
Often you won't need this flexibility, a Simple Lens
takes 2 parameters, and can be used directly as a Lens
.
You can also write to setters that target multiple parts of a structure, or their composition with other lenses or setters. The canonical example of a setter is 'mapped':
mapped :: Functor f => Setter (f a) (f b) a b
over
is then analogous to fmap
, but parameterized on the Setter.
ghci> fmap succ [1,2,3]
[2,3,4]
ghci> over mapped succ [1,2,3]
[2,3,4]
The benefit is that you can use any Lens
as a Setter
, and the composition of setters with other setters or lenses using (.)
yields
a Setter
.
ghci> over (mapped._2) succ [(1,2),(3,4)]
[(1,3),(3,5)]
(%~)
is an infix alias for 'over', and the precedence lets you avoid swimming in parentheses:
ghci> _1.mapped._2.mapped %~ succ $ ([(42, "hello")],"world")
([(42, "ifmmp")],"world")
There are a number of combinators that resemble the +=
, *=
, etc. operators from C/C++ for working with the monad transformers.
There are +~
, *~
, etc. analogues to those combinators that work functionally, returning the modified version of the structure.
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. Combinators are included that are based on Neil Mitchell's uniplate
, but which
have been generalized to work on or as lenses, folds, and traversals.
ghci> :m + Data.Data.Lens
ghci> anyOf biplate (=="world") ("hello",(),[(2::Int,"world")])
True
As alluded to above, 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)]
Moreover, many of the lenses supplied are actually isomorphisms, that means you can use them directly as a lens or getter:
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.
There are also a couple of hundred examples distributed throughout the haddock documentation.
Operators
(See wiki/Operators
)
Combinator(s) | w/ Result | Stateful | w/ Result | Notes | |||
---|---|---|---|---|---|---|---|
Control.Lens | |||||||
view ,views ,^. |
use ,uses |
View target(s). query works like use over a MonadReader |
|||||
set , .~ |
<.~ |
.= |
assign ,<.= |
Replace target(s). <<.~ and
<<.=
return the old value | |||
over ,mapOf ,%~ |
<%~ | %= |
<%= | Update target(s). <<%~ and
<<%=
return the old value | |||
id ,traverseOf ,%%~ |
%%= |
Update target(s) with an Applicative or auxiliary result |
|||||
+~ |
<+~ | += |
<+= | Add to target(s) | |||
-~ |
<-~ | -= |
<-= | Subtract from target(s) | |||
*~ |
<*~ | *= |
<*= | Multiply target(s) | |||
//~ |
<//~ | //= |
<//= | Divide target(s) | |||
^~ |
<^~ | ^= |
<^= | Raise target(s) to a non-negative Integral power |
|||
^^~ |
<^^~ | ^^= |
<^^= | Raise target(s) to an Integral power |
|||
**~ |
<**~ | **= |
<**= | Raise target(s) to an arbitrary power | |||
||~ |
<||~ | ||= |
<||= | Logically or target(s) | |||
&&~ |
<&&~ | &&= |
<&&= | Logically and target(s) | |||
<>~ |
<<>~ | <>= |
<<>= | mappend to the target monoidal value(s) |
|||
headOf ,^? | Return Just the first target or Nothing |
||||||
toListOf ,^.. | Return a list of the target(s) | ||||||
perform ,performs ^! |
Perform monadic action(s) | ||||||
Control.Lens (Indexed) | |||||||
iover ,imapOf ,%@~ |
<%@~ | %@= |
<%@= | Update target(s) with access to the index. | |||
withIndex ,itraverseOf ,%%@~ |
%%@= |
Update target(s) with an Applicative or auxiliary result with access to the index. |
|||||
Data.Bits.Lens | |||||||
.|.~ |
<.|.~ | .|.= |
<.|.= | Bitwise or target(s) | |||
.&.~ |
<.&.~ | .&.= |
<.&.= | Bitwise and target(s) | |||
System.FilePath.Lens | |||||||
</>~ |
<</>~ | </>= |
<</>= | Append a relative path to a FilePath |
|||
<.>~ |
<<.>~ | <.>= |
<<.>= | Append a file extension to a FilePath |
|||
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