Firstly, what is lens/lenses/optics?

- A really great solution to the "records problem"
- An almost accidental discover
- Ridiculously complicated type level playground
- Collections of lots of different related things
- The first real subtyping solution in Haskell
- A complete language based on Haskell

## The records problem

Imagine a nested data structure:

data Address = Address { addressCity :: !Text , addressStreet :: !Text } data Person = Person { personAddress :: !Address , personName :: !Text }

If you have a value `alice :: Person`

, and you want to get the
person's city, you can use record accessors as normal functions:

getPersonCity :: Person -> Text getPersonCity = addressCity . personAddress alice'sCity :: Text alice'sCity = getPersonCity alice

That's pretty elegant. But let's say that you want to change Alice's city to something else. In a mutable, object-oriented language, you'd probably expect something like:

```
alice.address.city = "Los Angeles";
```

The first issue in Haskell is that we can't mutate `alice`

; we instead
have to return a *new* `Person`

value with the updated city. Type
signature wise, we'd be looking at:

setPersonCity :: Text -> Person -> Person

That makes sense. Now let's see how we'd implemente this:

import Data.Text (Text) data Address = Address { addressCity :: !Text , addressStreet :: !Text } data Person = Person { personAddress :: !Address , personName :: !Text } getPersonCity :: Person -> Text getPersonCity = addressCity . personAddress setPersonCity :: Text -> Person -> Person setPersonCity city person = person { personAddress = (personAddress person) { addressCity = city } }

Well... that obviously sucks. It only gets worse as the nesting levels go deeper. Let's look at some ways to make this easier to stomach.

## Modifier functions

Let's see if we can make this slightly less painful with some modifier functions:

modifyAddressCity :: (Text -> Text) -> Address -> Address modifyAddressCity f address = address { addressCity = f (addressCity address) } modifyPersonAddress :: (Address -> Address) -> Person -> Person modifyPersonAddress f person = person { personAddress = f (personAddress person) } modifyPersonCity :: (Text -> Text) -> Person -> Person modifyPersonCity = modifyPersonAddress . modifyAddressCity setPersonCity :: Text -> Person -> Person setPersonCity city = modifyPersonCity (const city)

Composing the modifier functions works nicely, and then we can easily convert a modifier function into a setter function. Writing the initial modifier functions is tedious, but that's the price of doing business.

Another downside is that we've totally separated out the getter and modifier functions. Let's see if we can combine those.

## Old style lenses

If our problem is splitting up the getters and modifiers, let's just stick them together.

data Lens s a = Lens { lensGetter :: s -> a , lensModify :: (a -> a) -> s -> s }

Previously we could compose our getters and modifiers with the good
old `.`

function composition operator, but now we need something a bit
more specialized:

composeLens :: Lens a b -> Lens b c -> Lens a c composeLens (Lens getter1 modify1) (Lens getter2 modify2) = Lens { lensGetter = getter2 . getter1 , lensModify = modify1 . modify2 }

With that in hand, we can write lenses for an address's city, a person's address, put them together, and then easily extract a setter:

personAddressL :: Lens Person Address personAddressL = Lens { lensGetter = personAddress , lensModify = \f person -> person { personAddress = f (personAddress person) } } addressCityL :: Lens Address Text addressCityL = Lens { lensGetter = addressCity , lensModify = \f address -> address { addressCity = f (addressCity address) } } personCityL :: Lens Person Text personCityL = personAddressL `composeLens` addressCityL setPersonCity :: Text -> Person -> Person setPersonCity city = lensModify personCityL (const city)

This works, but it feels clunky. It also has some performance overhead
we didn't have previously due to the creation of the `Lens`

values. And a more advanced topic we haven't even touched on yet: it
doesn't allow for *polymorphic update*, which deals with changing type
variables (we won't deal with that for now).

## Van Laarhoven lenses

In all honesty, understanding exactly how these next forms of lenses work isn't strictly necessary. It's built on the same premise as the previous kinds of lenses, but it's:

- More efficient
- More easily composable
- Generalizes to other cases
- Handles polymorphic updates
- Produces much crazier error messages

Let's start slowly in motivating this. Our first goal is to see if we can combine our getter and modifier into a single value, without using a product type. We need to be able to extract both a getter and modifier from this value, so it has to provide the following:

type Lens s a = ? view :: Lens s a -> s -> a view = ? over :: Lens s a -> (a -> a) -> s -> s over = ?

(Ignore the funny names, they're part of `lens`

.)

It doesn't seem like those two output types (`s -> a`

and `(a -> a) -> s -> s`

) have much in common. But we're going to use a trick to make
them match up. Let's start with the `over`

result:

(a -> a) -> (s -> s)

I'm going to wrap up the results of the two functions inside the
`Identity`

functor:

newtype Identity a = Identity { runIdentity :: a } deriving Functor type LensModify s a = (a -> Identity a) -> (s -> Identity s) over :: LensModify s a -> (a -> a) -> s -> s over lens f s = runIdentity (lens (Identity . f) s)

And we can create values for this lens type with:

personAddressL :: LensModify Person Address personAddressL f person = Identity $ person { personAddress = runIdentity $ f $ personAddress person }

Or, if we want to take advantage of the `Functor`

instance and not
play with wrapping and unwrapping the `Identity`

values, we get:

personAddressL :: LensModify Person Address personAddressL f person = (\address -> person { personAddress = address }) <$> f (personAddress person)

Alright, let's switch over to the getter side. This time around, we
want to start with the same basic `(a -> a) -> (s -> s)`

, but apply a
*different* wrapper type to allow us to get a getter function at the
end, `s -> a`

. So in other words, we need to be able to convert from
`s -> Wrapper s`

to `s -> a`

. This may seem impossible at first, but
it turns out that there's a cool trick to make this happen:

newtype Const a b = Const { getConst :: a } deriving Functor type LensGetter s a = s -> Const a s view :: LensGetter s a -> s -> a view lens s = getConst (lens s) personAddressL :: LensGetter Person Address personAddressL person = Const (personAddress person)

This is fairly complex. `Const`

is a data type that does the same
thing as the `const`

function: it holds onto one value and ignores a
second. Here, `Const`

is keeping our `Address`

value for us and
allowing use to extract it inside `view`

. Stare at it a while and it
will make sense, but it's also just a convoluted way to get to our
goal.

Ultimately, our goal is to make `LensGetter`

and `LensModify`

the same
thing. But right now, they don't look very similar.

type LensModify s a = (a -> Identity a) -> (s -> Identity s) type LensGetter s a = s -> Const a s

In order to bring them more inline, we need to redefine `LensGetter`

as:

type LensGetter s a = (a -> Const a s) -> (s -> Const a s)

And it turns out by shuffling around some things just a bit, we can make this work as well:

type LensGetter s a = (a -> Const a a) -> (s -> Const a s) view :: LensGetter s a -> s -> a view lens s = getConst (lens Const s) personAddressL :: LensGetter Person Address personAddressL f person = Const $ getConst $ f (personAddress person)

Again, kind of crazy, but it works. Our wrapper type is now `Const a`

,
and we pass in the `Const`

data constructor to the `lens`

. It all
kinda sorta works. One final tweak on all of this. Previously, we
defined our modify lens using the `Functor`

interface so we didn't
need to know about `Identity`

at all:

personAddressL :: LensModify Person Address personAddressL f person = (\address -> person { personAddress = address }) <$> f (personAddress person)

It turns out that this *exact same function body* works for defining
`LensGetter`

:

personAddressL :: LensGetter Person Address personAddressL f person = (\address -> person { personAddress = address }) <$> f (personAddress person)

And now we can finally unify our getter and modify lenses into one:

type Lens s a = forall f. Functor f => (a -> f a) -> (s -> f s) newtype Identity a = Identity { runIdentity :: a } deriving Functor newtype Const a b = Const { getConst :: a } deriving Functor over :: Lens s a -> (a -> a) -> s -> s over lens f s = runIdentity (lens (Identity . f) s) view :: Lens s a -> s -> a view lens s = getConst (lens Const s) personAddressL :: Lens Person Address personAddressL f person = (\address -> person { personAddress = address }) <$> f (personAddress person) getPersonAddress :: Person -> Address getPersonAddress = view personAddressL modifyPersonAddress :: (Address -> Address) -> Person -> Person modifyPersonAddress = over personAddressL setPersonAddress :: Address -> Person -> Person setPersonAddress address = modifyPersonAddress (const address)

This means that we have a lens if we support *all possible functors*
in that type signature. It turns out, almost as if by magic, that this
allows us to recapture getter and modifier functions (and via
modifier, setter functions).

The formulation is wonky, and very difficult to grasp. Don't worry if the intuition hasn't kicked in. It turns out that you can use lenses quite a bit without fully grokking them.

## Composing lenses

First, let's define a helper function for turning a getter and a setter into a lens:

lens :: (s -> a) -> (s -> a -> s) -> Lens s a lens getter setter = \f s -> setter s <$> f (getter s)

Then we can more easily define lenses for `person.address`

and
`address.city`

:

personAddressL :: Lens Person Address personAddressL = lens personAddress (\x y -> x { personAddress = y }) addressCityL :: Lens Address Text addressCityL = lens addressCity (\x y -> x { addressCity = y })

How do we compose them together into the `person.address.city`

lens?
If we expand the type signatures a bit it may become obvious:

personAddressL :: Functor f => (Address -> f Address) -> (Person -> f Person) addressCityL :: Functor f => (Text -> f Text) -> (Address -> f Address) personCityL :: Functor f => (Text -> f Text) -> (Person -> f Person)

How would you implement `personCityL`

? Well, turns out to be really
easy:

personCityL :: Lens Person Text personCityL = personAddressL.addressCityL

This is a great strength of lenses: *they work with normal function
composition*. They also work in what Haskellers would consider
*backwards* order: the composition seems to flow from left to right
instead of right to left. But on the other hand, this seems to match
up perfectly with what object oriented developers expect, so that's
nice.

## Helper functions and operators

Dealing directly with the `Lens`

type is needlessly painful. Instead,
we work through helper functions and operators. You've already seen
`view`

, `over`

, and `lens`

. Let's implement a few more:

(^.) :: s -> Lens s a -> a s ^. lens = view lens s infixl 8 ^. (%~) :: Lens s a -> (a -> a) -> s -> s (%~) = over infixr 4 %~ reverseCity :: Person -> Person reverseCity = personAddressL.addressCityL %~ T.reverse getCity :: Person -> Text getCity person = person ^. personAddressL.addressCityL set :: Lens s a -> a -> s -> s set lens a s = runIdentity $ lens (\_olda -> Identity a) s setCity :: Text -> Person -> Person setCity = set (personAddressL.addressCityL)

## Polymorphic updates

It turns out that we can make lenses a bit more general. If we look at the current type:

type Lens s a = forall f. Functor f => (a -> f a) -> (s -> f s)

It requires that the field originally be of type `a`

and ultimately of
type `a`

. It also requires that the value overall is of type `s`

and
ultimately of type `s`

. Let's create a new datatype where this would
be limiting:

data Person age = Person { personName :: !Text , personAge :: !age } aliceInt :: Person Int aliceInt = Person "Alice" 30 personAgeL :: Lens (Person age) age personAgeL = lens personAge (\x y -> x { personAge = y }) setAge :: age -> Person oldAge -> Person age setAge age person = person { personAge = age } aliceDouble :: Person Double aliceDouble = setAge 30.5 aliceInt

Try as we might, we cannot use `personAgeL`

to change the age value
from an `Int`

to a `Double`

. Its construction requires that the input
and output `age`

type variable remain the same. However, with a small
extension to our `Lens`

type, we can make this work:

type Lens s t a b = forall f. Functor f => (a -> f b) -> (s -> f t) -- Our old monomorphic variant type Lens' s a = Lens s s a a

This says that we have some data structure, `s`

. Inside `s`

is a value
`a`

. If you replace that `a`

with a `b`

, you get out a `t`

. Sound
weird? Let's see it in practice:

personAgeL :: Lens (Person age1) (Person age2) age1 age2 personAgeL = lens personAge (\x y -> x { personAge = y }) setAge :: age -> Person oldAge -> Person age setAge = set personAgeL

## Getters, setters, folds, traversals...

What we've seen so far is the original motivating case. It turns out
that there are many crazy ways of generalizing a `Lens`

further to
represent more usages. This comes by means of various techniques, such
as:

- Using concrete types
- Using a different typeclass constraint from
`Functor`

- Replace functions (e.g.,
`a -> f b`

) with profunctors (e.g.`p a (f b)`

)

We've already seen examples of the concrete types approach. Let's use their more standard names now:

type ASetter s t a b = (a -> Identity b) -> s -> Identity t type ASetter' s a = ASetter s s a a type Getting r s a = (a -> Const r a) -> s -> Const r s type SimpleGetter s a = forall r. Getting r s a

By using different typeclasses, we're able to create a form of
subtyping. For example, every `Applicative`

is also a `Functor`

. So if
we define a new type like this:

type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t

Every `Lens s t a b`

is also a `Traversal s t a b`

, but the reverse is
not true. We can go even deeper down the rabit hole with:

type Fold s a = forall f. (Contravariant f, Applicative f) => (a -> f a) -> s -> f s

Now we need `f`

to be both `Applicative`

and `Contravariant`

, so that
all `Traversal`

s are `Fold`

s, but not all `Fold`

s are
`Traversal`

s. This actually matches up with the related typeclasses
`Foldable`

and `Traversable`

, where the latter is a subclass of the
former.

*But what does this have to do with field accessors?* you may
ask. This is what I was implying above with lens being its own
language on top of Haskell: if desired, you can replace a lot of
functionality found elsewhere with lens-centric code. All of these
different types I've mentioned are known as *optics*, and since they
all have roughly the same shape, they compose together very nicely.

## Packages

The `lens`

package itself is fully loaded, and provides *lots* of
helper functions, operators, types, and generality. It also has a
relatively heavy dependency footprint. Many projects instead use
`microlens`

, which has a much lighter footprint, but also lacks some
functionality (for example, prisms).

## Template Haskell

If writing those lenses above by hand seems tedious to you, you're not alone. Many people use macros/code generation/Template Haskell (all the same thing in Haskell) to automatically generate lenses, and sometimes typeclasses to generalize them. Examples:

- https://www.stackage.org/haddock/lts-12.21/microlens-th-0.4.1.1/Lens-Micro-TH.html
- https://www.stackage.org/haddock/lts-12.21/lens-4.15.4/Control-Lens-TH.html

## Best practices

The most important decision to be made for a team is *how* to use
lenses. Best practices are vital. You do not want half the team using
advanced lens features and the other half not understanding them at
all. I can advise on what I consider best practices, but it will
depend a lot on how your team wants to approach things. What I've
standardized on:

- Using the basic
`Lens`

types and its functions: solid gold, do it, don't hold back! The biggest downside is the slightly confusing error messages, but you get used to that quickly - Replacing common library functions (like
`lookup`

) with their lensy counterparts (like`at`

): not worth it. You'll make your code shorter, but I prefer the standard Haskell idioms to relearning with lens. - Advanced techniques like prisms, folds, traversals: soft avoidance on my part. I think usually the standard Haskell techniques are better suited, but again you'll be able to code golf more easily with the optics. Prisms in particular are, in my experience, a ripe source of bugs, where pattern matching can lead to much clearer code.

We should base the homework exercises around how deeply into lenses the team wants to go.

## Exercise 1

Fill out the stubs below to make the test suite pass. Probably goes
without saying, but: use the generated lenses (`address`

, `street`

,
`age`

, etc) wherever possible instead of falling back to records.

#!/usr/bin/env stack -- stack --resolver lts-12.21 script {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} import Lens.Micro.Platform import Data.Text (Text) import Test.Hspec data Address = Address { _street :: !Text , _city :: !Text } makeLenses ''Address data Person = Person { _name :: !Text , _address :: !Address , _age :: !Int } makeLenses ''Person hollywood :: Text hollywood = "Hollywood Blvd" alice :: Person alice = Person { _name = "Alice" , _address = Address { _street = hollywood , _city = "Los Angeles" } , _age = 30 } wilshire :: Text wilshire = "Wilshire Blvd" aliceWilshire :: Person aliceWilshire = _ -- FIXME set Alice's street to Wilshire getStreet :: Person -> Text getStreet = _ -- | Increase age by 1 birthday :: Person -> Person birthday = _ getAge :: Person -> Int getAge = _ main :: IO () main = hspec $ do it "lives on Wilshire" $ _street (_address aliceWilshire) `shouldBe` wilshire it "getStreet works" $ getStreet alice `shouldBe` hollywood it "birthday" $ getAge (birthday alice) `shouldBe` _age alice + 1

## Exercise 2

Remove the `{-# LANGUAGE TemplateHaskell #-}`

line from the previous
exercise and get the code to compile. You'll need to define your own
lenses to make this work. Use the `lens`

helper function, and make
sure to add type signatures to the values you create.

## Exercise 3

Real challenge: now implement those lenses again, but without using
the `lens`

helper function. Instead, use `fmap`

or `<$>`

directly.

## Exercise 4

There are tuple lenses provided, named `_1`

, `_2`

, and so on, for
modifying components in tuples. Fill in the stub below so that the
test passes:

#!/usr/bin/env stack -- stack --resolver lts-12.21 script {-# LANGUAGE OverloadedStrings #-} import Lens.Micro.Platform import Test.Hspec main :: IO () main = hspec $ it "fun with tuples" $ let tupleLens = _ tuple :: ((Int, Double), (Bool, Char, String)) tuple = ((1, 2), (True, 'x', "Hello World")) in over tupleLens not tuple `shouldBe` ((1, 2), (False, 'x', "Hello World"))

## Exercise 5

Everything we've done so far has been on *product types*. In these
cases, lenses work perfectly: we know that we have every field
available. However, lenses do not work perfectly on *sum types*, where
values may or may not exist. In these cases, prisms, traversals, and
folds come into play. We're not necessarily going to be using these in
depth, but it's good to be aware of them.

Let's use the `_Left`

and `_Right`

prisms (which work as traversals
and folds as well). Fill in the expected values for the test suite
below to begin to get an intuition for how the traversal functions
work.

#!/usr/bin/env stack -- stack --resolver lts-12.21 script import Lens.Micro.Platform import Test.Hspec main :: IO () main = hspec $ do it "over left on left" $ let val :: Either Int Double val = Left 5 in over _Left (+ 1) val `shouldBe` _ it "over left on right" $ let val :: Either Int Double val = Right 5 in over _Left (+ 1) val `shouldBe` _ it "set left on left" $ let val :: Either Int Double val = Left 5 in set _Left 6 val `shouldBe` _ it "set left on right" $ let val :: Either Int Double val = Right 5 in set _Left 6 val `shouldBe` _

## Exercise 6

Bonus! This one makes more extreme usage of the folds and traversals. Reimplement some common library functions using lenses. This will require looking through the docs for microlens or lens quite a bit.

#!/usr/bin/env stack -- stack --resolver lts-12.21 script {-# OPTIONS_GHC -Wall -Werror #-} {-# LANGUAGE RankNTypes #-} import Lens.Micro.Platform import Test.Hspec import Data.Monoid (Endo) -- | map/fmap mapLens :: ASetter s t a b -> (a -> b) -> s -> t mapLens = _ -- | toList toListLens :: Getting (Endo [a]) s a -> s -> [a] toListLens = _ -- | catMaybes catMaybesLens :: [Maybe a] -> [a] catMaybesLens = _ main :: IO () main = hspec $ do it "mapLens" $ mapLens _2 not ((), True) `shouldBe` ((), False) it "toListLens" $ toListLens both ('x', 'y') `shouldBe` "xy" it "catMaybesLens" $ catMaybesLens [Just 'x', Nothing, Just 'y'] `shouldBe` "xy"

## Solutions

### Exercise 1

Note that there are many other ways to solve some of these problems.

#!/usr/bin/env stack -- stack --resolver lts-12.21 script {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} import Lens.Micro.Platform import Data.Text (Text) import Test.Hspec data Address = Address { _street :: !Text , _city :: !Text } makeLenses ''Address data Person = Person { _name :: !Text , _address :: !Address , _age :: !Int } makeLenses ''Person hollywood :: Text hollywood = "Hollywood Blvd" alice :: Person alice = Person { _name = "Alice" , _address = Address { _street = hollywood , _city = "Los Angeles" } , _age = 30 } wilshire :: Text wilshire = "Wilshire Blvd" aliceWilshire :: Person aliceWilshire = set (address.street) wilshire alice getStreet :: Person -> Text getStreet = view (address.street) --getStreet = (^. address.street) -- | Increase age by 1 birthday :: Person -> Person birthday = over age (+ 1) --birthday = age %~ (+ 1) getAge :: Person -> Int getAge = view age main :: IO () main = hspec $ do it "lives on Wilshire" $ _street (_address aliceWilshire) `shouldBe` wilshire it "getStreet works" $ getStreet alice `shouldBe` hollywood it "birthday" $ getAge (birthday alice) `shouldBe` _age alice + 1

### Exercise 2

street :: Lens' Address Text street = lens _street (\x y -> x { _street = y }) address :: Lens' Person Address address = lens _address (\x y -> x { _address = y }) age :: Lens' Person Int age = lens _age (\x y -> x { _age = y })

### Exercise 3

street :: Lens' Address Text street f address = (\x -> address { _street = x }) <$> f (_street address) address :: Lens' Person Address address f person = (\x -> person { _address = x }) <$> f (_address person) age :: Lens' Person Int age f person = (\x -> person { _age = x }) <$> f (_age person)

### Exercise 4

let tupleLens = _2._1

### Exercise 5

The most important bit here to notice: using `set _Left`

did *not*
change the data constructor from `Right`

to `Left`

.

#!/usr/bin/env stack -- stack --resolver lts-12.21 script import Lens.Micro.Platform import Test.Hspec main :: IO () main = hspec $ do it "over left on left" $ let val :: Either Int Double val = Left 5 in over _Left (+ 1) val `shouldBe` Left 6 it "over left on right" $ let val :: Either Int Double val = Right 5 in over _Left (+ 1) val `shouldBe` Right 5 it "set left on left" $ let val :: Either Int Double val = Left 5 in set _Left 6 val `shouldBe` Left 6 it "set left on right" $ let val :: Either Int Double val = Right 5 in set _Left 6 val `shouldBe` Right 5

### Exercise 6

#!/usr/bin/env stack -- stack --resolver lts-12.21 script {-# OPTIONS_GHC -Wall -Werror #-} {-# LANGUAGE RankNTypes #-} import Lens.Micro.Platform import Test.Hspec import Data.Monoid (Endo) -- | map/fmap mapLens :: ASetter s t a b -> (a -> b) -> s -> t mapLens l f = over l f -- | toList toListLens :: Getting (Endo [a]) s a -> s -> [a] toListLens l s = s ^.. l -- | catMaybes catMaybesLens :: [Maybe a] -> [a] catMaybesLens list = list ^.. each._Just main :: IO () main = hspec $ do it "mapLens" $ mapLens _2 not ((), True) `shouldBe` ((), False) it "toListLens" $ toListLens both ('x', 'y') `shouldBe` "xy" it "catMaybesLens" $ catMaybesLens [Just 'x', Nothing, Just 'y'] `shouldBe` "xy"