I learned lens about 6 months ago and I thought it an fascinating concept. The idea, the abstraction, the implementation and the final DSL it achieve are exciting. But also, it’s very complicated not only by itself, but also the related topics of functional programming and theory. Now I almost forgot everything but the thrill of learning it. Now I want to re-learn this beautiful thing and try not to forget that again. So here come this series of post.

To be honest, the theories behind *lens* is way beyond my current capability, so there’s a high chance for me to make mistakes, explain subtle topic inaccurately or imprecisely through these upcoming posts. So please point them out (by email or whatever way to contact me) should that happen, I would appreciate it very much!

Now onward!

## What is “Lens”

“Lens”es are generally considered to be “functional references” to sub-objects inside “parent” objects, such as a data field of a (object-oriented) class, the second element of a two-tuple, 4th element in a list etc. Lens push this idea to a more general perspective, we can say “every element that’s equal to one”, “sum of the elements in the list”, “reverse view of the string itself”. Moreover, Lens solves this problem in a purely functional, composable, therefore elegant way.

Let’s look at several examples from official repository of haskell implementation:

*assuming _1, _2 are lenses referencing to the first and the second field of an tuple*

```
-- get
ghci> ("hello","world") ^. _2
"world" --"get" operator ^
-- set
ghci> set _2 42 ("hello","world")
("hello",42)
-- composition
ghci> ("hello",("world","!!!")) ^. _2 . _1
"world" -- function composition itself ^
-- manipulation
ghci> ("hello",("world","!!!")) ^. _2 . _2 . to length
3
```

It looks amazingly clean syntax-wise, but it’s a little too clean for now. Ignoring many other complexities, lenses here seem to act like a combination of “getter” and “setter”, so that they can answer the corresponding request they’ve asked to. Of course that’s the intuition of “sub-object reference” after all – just retrieving the value or modifying them. So let’s look at these two “component”s of lens separately and try to combine them together.

## Abstractions

### Getter

This is a relatively simpler one, who doesn’t know how to access a value. Recalling getting element out of a tuple.

```
fst :: (a, b) -> a
snd :: (a, b) -> b
```

That’s simple enough, but we probably want more generality. What about:

```
type Getter s a = s -> a
fst :: Getter (a, b) a
snd :: Getter (a, b) b
```

Now we are mostly good, but we don’t always want whatever we’re getting out, we probably want to preserve the option to transform the result to some other thing as the result.
We certainly can do that with function composition, but we have another way to do that without the help of the compose operator. Let’s add some CPS taste to our `Getter`

.

```
type Getter r s a = (a -> r) -> s -> r
getFst :: Getter (a, b) a c
fst = getFst id
getSnd :: Getter (a, b) b c
snd = getSnd id
```

That’s better, let’s move on to our setter.

### Setter

Let’s first define our tuple setters. Of course in a pure language as haskell, we cannot directly “set” the original object, the common pattern is that we return a new copy instead.

```
setFst :: a -> (a, b) -> (a, b)
setSnd :: b -> (a, b) -> (a, b)
```

The first thing we notice is that we don’t always have the value to set, we usually want to “update” the object depending on the original value. Let’s fit this idea into our setter.

```
type Setter s a = (a -> a) -> s -> s
setFst :: Setter (a, b) a
setSnd :: Setter (a, b) b
```

But wait, it’s not really necessary to always set the sub-object to a value of the same type, which is quite obvious in this tuple example.

```
type Setter s t a b = (a -> b) -> s -> t
setFst :: Setter (a, b) (c, b) a c
setFst ac (a, b) = (ac a, b)
setSnd :: Setter (a, b) (a, c) b c
setSnd bc (a, b) = (a, bc b)
```

## Getter + Setter

Next step, let’s put getter and setter together. Recall our `Getter`

and `Setter`

definition

```
type Getter r s a = (a -> r) -> s -> r
type Setter s t a b = (a -> b) -> s -> t
```

Note that, one thing that trapped me is, although at first glance `a -> r`

and `a -> b`

looks rather similar, but they convey different meanings.
`r`

is just the whatever result returned by the continuation, but `b`

is the actual thing we want to set to `s`

.

So how can we stick them together? Although `r`

and `b`

don’t mean the same, but two types still share a very similar structure. Our first try would be:

### GetAndSet

```
type GetAndSet r s t a b = (a -> (r, b)) -> s -> (r, t)
getAndSetFst :: GetAndSet r (x, y) (z, y) x z
getAndSetFst xrz (x, y) = let (r, z) = xrz x in (r, (z, y))
-- or using the fact that `(r, )` is a functor
getAndSetFst xrz (x, y) = flip (,) y <$> xrz x
```

It works, but clearly it doesn’t look very elegant.

Interestingly enough, one thing we observed above is that `(r, b)`

is actually a functor with respect to `b`

. Why does that matter?
Because now `(r, b) -> (r, t)`

suddenly becomes a functor operation (`fmap`

), which indicates that what we don’t really have to break down the tuple `(r, b)`

to get the final result, we just care about the `b -> t`

part of it.

Another problem of this abstraction is, as the type name suggest, it’s a setter **and** a getter.
But it’s not very often we want them both **simultaneously**. When we’re calling “get”, we don’t need the setter at all, when we’re calling “set”, we don’t need the getter at all.

### GetOrSet

Exploiting the functor operation, we can use `Either`

instead.

```
type GetOrSet r s t a b = (a -> Either r b) -> s -> Either r t
getOrSetFst :: GetOrSet r (x, y) (z, y) x z
getOrSetFst xrz (x, y) = flip (,) y <$> xrz x -- exact same implementation
```

Now it can behave like a setter or a getter depending on the situation, we are getting there!

```
getLeft :: Either a b -> a
getLeft (Left a) = a
getRight :: Either a b -> b
getRight (Right b) = b
get :: GetOrSet a s t a b -> s -> a
get gos = getLeft . gos Left
set :: GetOrSet r s t a b -> (a -> b) -> s -> t
set gos ab = getRight . gos (Right . ab)
```

Let’s try it:

```
𝝺 > get getOrSetFst (1, 2)
1
𝝺 > set getOrSetFst length ("abc", 2)
(3,2)
```

## Type Refinement

Great, but the use of `getLeft`

and `getRight`

here is annoying, calling an untotal function in functional programming always isn’t a good idea.
But since we know that we will be getting out `Left`

if we produce a `Left`

and vice versa, we are fine as long as the implementation of `GetOrSet`

is reasonable.

But anyway, if we think about it, `get`

always only use the `Left`

and `set`

always only use the `Right`

, let’s step back and try to express that in the type signature of `get`

and `set`

.

`Const`

, the functor that does nothing

`fmap`

ing an `Either`

contains a `Left`

doesn’t do anything. Is there a functor that contains only the `Left`

case of `Either`

? There is! The `Const`

functor:

```
-- Data.Functor.Const
newtype Const a b = Const { getConst :: a }
instance Functor (Const a) where
fmap _ (Const a) = Const a
```

That type looks really dumb at first glance, but this turns out to be exactly what we need now! So that the `get`

becomes:

```
type Getter r s t a b = (a -> Const r b) -> s -> Const r t
get :: Getter a s t a b -> s -> a
get getter = getConst . getter Const
```

Let’s move on to `set`

`Identity`

, the functor of “no functor”

Ignoring the `Left`

part of `Either`

means … Eh, if we look back, we don’t really need any functor there, `(a -> b) -> s -> t`

is just fine. But if we really want to add one, for the greater good… I would say `Identity`

.

```
-- Data.Functor.Identity
newtype Identity a = Identity { getIdentity :: a }
instance Functor Identity where
fmap f (Identity a) = Identity $ f a
type Setter s t a b = (a -> Identity b) -> s -> Identity t
set :: Setter s t a b -> (a -> b) -> s -> t
set setter f = runIdentity . setter (Identity . f)
```

`Lens`

Now, the instances of `Functor`

used by `Setter`

and `Getter`

is the only difference in the type alias definitions. We could extract it with another type alias:

```
type LensLike f s t a b = (a -> f b) -> s -> f t
type Setter s t a b = LensLike Identity s t a b
type Getter r s a = LensLike (Const r) s s a a
```

However, this way we lose the information that `f`

is required to be a `Functor`

,
but we can NOT add a type class constraint to the `type`

alias definition like `type Functor f => Lens f ...`

.

What we could make use of the `RankNTypes`

language extension, and completely abstract out the type parameter
in the head of the declaration to the body of type like so:

```
type Lens s t a b = forall f. Functor f => LensLike f s t a b
-- `setOrGetFst` with exactly the same implementation
_1 :: Lens (x, y) (z, y) x z
_1 f (x, y) = flip (,) y <$> f x
-- same definition as above
set :: Setter s t a b -> (a -> b) -> s -> t
set' :: Setter s t a b -> b -> s -> t
set' setter = set setter . const
```

With `RandNTypes`

, we don’t even mention the type parameter `f`

in `_1`

,
because the `f`

is abtracted out directly in the type, and is no longer a
“type variable” of the type alias. And we could still use a `Lens`

as a `Setter`

or `Getter`

like so:

```
𝝺> set _1 (+1) (1, 'a')
(2,'a')
𝝺> get _1 (+1) (1, 'a')
2
```

During type checking, ghc notices that the type `forall f. Functor f => (a -> f b) -> (s -> f t)`

is compatible to both type `(a -> Identity b) -> (s -> Identity t)`

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

,
because both `Identity`

and `Const`

are functors, which satisfy the `Functor`

constraint in the `forall`

quantified type.

## Back to Reality

Now we “almost” achieve what we saw before, we have a clean design of `Setter`

and `Getter`

type and both of which related to `Lens`

, we didn’t quite obey the naming in the implementation in the library, and some types have *slightly* different signatures.

The actual type signatures are defined in

```
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
type Lens' s a = Lens s s a a
type LensLike f s t a b = (a -> f b) -> s -> f t
type LensLike' f s a = LensLike f s s a a
-- `Settable` constraint is mostly talking about `Identity`
type Setter s t a b = forall f. Settable f => (a -> f b) -> s -> f t
type Setter' s a = Setter s s a a
type ASetter s t a b = (a -> Identity b) -> s -> Identity t
-- `set` in our article
over :: ASetter s t a b -> (a -> b) -> s -> t
-- `set'` in our article
set :: ASetter s t a b -> b -> s -> t
-- `Getter` in our article
type Getting r s a = (a -> Const r a) -> s -> Const r s
-- again, the constraint is mostly talking about `Const`
type Getter s a = forall f. (Contravariant f, Functor f) => (a -> f a) -> s -> f s
-- a simple "getter"
(^.) :: s -> Getting a s a -> a
-- some magic combined with (.^) to obtain a behavior of `get` in our article
to :: (Profunctor p, Contravariant f) => (s -> a) -> Optic' p f s a
```

## Conclusion

In this article, we kinda “derived” the design of `Lens`

informally, and in the next article
we would explore something left by this article, the composition of lenses,
and some magic constraints (like `Contravariant`

) in the real implementation.