Generate lenses for a data type or a newtype.
To use it, you have to enable Template Haskell first:
{-# LANGUAGE TemplateHaskell #-}
Then, after declaring the datatype (let's say Foo), add makeLenses ''Foo on a separate line (if you do it before the type is declared, you'll get a “not in scope” error – see the section at the top of this page):
data Foo = Foo {
_x :: Int,
_y :: Bool }
makeLenses ''Foo
This would generate the following lenses, which can be used to access the fields of Foo:
x :: Lens' Foo Int
x f foo = (\x' -> foo {_x = x'}) <$> f (_x foo)
y :: Lens' Foo Bool
y f foo = (\y' -> foo {_y = y'}) <$> f (_y foo)
(If you don't want a lens to be generated for some field, don't prefix it with “_”.)
If you want to create lenses for many types, you can do it all in one place like this (of course, instead you just can use makeLenses several times if you feel it would be more readable):
data Foo = ...
data Bar = ...
data Quux = ...
concat <$> mapM makeLenses [''Foo, ''Bar, ''Quux]
When the data type has type parameters, it's possible for a lens to do a polymorphic update – i.e. change the type of the thing along with changing the type of the field. For instance, with this type
data Foo a = Foo {
_x :: a,
_y :: Bool }
the following lenses would be generated:
x :: Lens (Foo a) (Foo b) a b
y :: Lens' (Foo a) Bool
However, when there are several fields using the same type parameter, type-changing updates are no longer possible:
data Foo a = Foo {
_x :: a,
_y :: a }
generates
x :: Lens' (Foo a) a
y :: Lens' (Foo a) a
Finally, when the type has several constructors, some of fields may not be always present – for those, a Traversal is generated instead. For instance, in this example y can be present or absent:
data FooBar
= Foo { _x :: Int, _y :: Bool }
| Bar { _x :: Int }
and the following accessors would be generated:
x :: Lens' FooBar Int
y :: Traversal' FooBar Bool
So, to get _y, you'd have to either use (^?) if you're not sure it's there, or (^?!) if you're absolutely sure (and if you're wrong, you'll get an exception). Setting and updating _y can be done as usual.