Jul 14, 2014

This article is the first in the upcoming series that aims to explain the
Haskell's `lens`

library and the
ideas behind it in an approachable way. Don't worry if you're new to Haskell,
the only prerequisites here should be understanding of the `Functor`

type
class, and understanding how records and algebraic data types work in Haskell.

We won't be using the `lens`

library in this article yet. The API we'll develop
will be exactly the same, but for the sake of learning I'll try to show you how
everything works and why it works by re-implementing it from scratch.

Keep in mind that lenses are a very advanced topic in Haskell and it takes some time to truly understand them. Don't worry if you don't understand everything at first read.

If you're coming from an imperative language like Ruby or Java, you're probably used to seeing code like this:

project.owner.name = "John"

The OOP people would call this **a violation of the Law of Demeter**, but let's
ignore that it's a bad practice for now. The question here is, can we achieve
something similar in Haskell?

data User = User { name :: String, age :: Int } deriving Show data Project = Project { owner :: User } deriving Show setOwnerName :: String -> Project -> Project setOwnerName newName p = p { owner = (owner p) { name = newName } }

Now we can already see how this is less than ideal. In order to change the name
of the `owner`

, we need to re-assign the owner field in the `Project`

with the
new `User`

, which is updated using the record syntax. We could do this in
multiple steps as follows.

Code blocks with `λ>`

denote GHCi session.

λ> let bob = User { name = "Bob", age = 30 } λ> let project = Project { owner = bob } λ> let alice = bob { name = "Alice" } λ> let project2 = project { owner = alice }

This is very tedious compared to the original Ruby example, especially since we need to keep re-building the original structure as we go deeper and deeper.

This is where lenses come to help you out. In essence, lenses are just getters and setters which you can compose together. In a naive approach the type might look something like the following:

data NaiveLens s a = NaiveLens { view :: s -> a , set :: a -> s -> s }

Following the convention of the official lens library
I've named the type parameters `s`

and `a`

, where `s`

is the *object* and `a`

is the *focus*. In our example above the `s`

would be `Project`

and `a`

would
be a `String`

, since we're trying to change the name of the project's user.

Now given a lens of type `NaiveLens User String`

we can easily change the
name of a user

λ> let john = User { name = "John", age = 30 } λ> set nameLens "Bob" john User {name = "Bob", age = 30}

How is such lens implemented? It's simply a getter and a setter.

nameLens :: NaiveLens User String nameLens = NaiveLens name (\a s -> s { name = a })

The problem with this approach of sticking a getter and a setter into a data
type is that it doesn't scale very well. If we wanted to do something like
*increment the value at the target by one*, we would have to first `view`

the
current value, apply +1 to it, and then `set`

the new value. We could
encapsulate this by providing the lens with a third function call `over`

:

over :: (a -> a) -> s -> s

We could use this similarly to `set`

.

λ> let john = User { name = "John", age = 30 } λ> over ageLens (+1) john User {name = "John", age = 31}

ageLens :: NaiveLens User Int ageLens = NaiveLens age (\a s -> s { age = a }) (\f s -> s { age = f (age s) })

The problem is that now we need to provide a getter and two setters for each lens, even if we just use one.

If you've been using Haskell for a while you've probably seen the magical
function `const`

. It's actually not magical at all, it simply has a type of ```
a
-> b -> a
```

, which allows us to turn `over :: (a -> a) -> s -> s`

into ```
set :: a
-> s -> s
```

by partially applying it, which leads to the definition of `set`

as
follows.

set :: NaiveLens s a -> a -> s -> s set ln a s = over ln (const a) s

Here's how the whole code looks now

data NaiveLens s a = NaiveLens { view :: s -> a , over :: (a -> a) -> s -> s } set :: NaiveLens s a -> a -> s -> s set ln a s = over ln (const a) s

Now we can see that `over`

is definitely useful, but what if our modifier
function needs to perform some side effects? For example we might want to send
the current value over the network to determine the new value. We could go on
as before and add yet another function called `overIO`

, which would look as the
following:

overIO :: (a -> IO a) -> s -> IO s

But this means our simple pair of a getter and a setter has grown into a getter
and two setters again. Not to mention that we might want to use `over`

in more
settings than just `IO`

. Here's how the type would look now.

data NaiveLens s a = NaiveLens { view :: s -> a , over :: (a -> a) -> s -> s , overIO :: (a -> IO a) -> s -> IO s }

This is the point where the magical generalization of what is called the *van
Laarhoven lens* comes into play. First step is that we can write our `overIO`

in a more general way by swapping `IO`

for a `Functor`

, which gives us the
following type.

overF :: Functor f => (a -> f a) -> s -> f s

For the sake of keeping this article short I'm going to tell you that `overF`

is everything we need in order to implement `view`

, `set`

, `over`

and `overIO`

.
Which means we no longer need a `Lens`

record type, since we'll have just one
function.

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

By making this a type alias instead of a `newtype`

or `data`

we get one amazing
property of lenses. You can define your own lenses without depending on the
`lens`

library. **Any function which has the appropriate type signature is a
lens**, there is no magic.

One thing to note here is that we do need to enable the
`RankNTypes`

extension for
this type alias to compile. To do that simply add the following snippet to the
first line of your file.

```
{-# LANGUAGE RankNTypes #-}
```

or if you're following along in GHCi type `:set -XRankNTypes`

. I won't be
explaining this in this article since it's quite a complicated topic, but if
you're interested in learning more, a simple google search will yield a lot of
good results.

`over`

, `set`

and `view`

in terms of `Lens s a`

Let's summarize before we move on. We started with an idea that a lens
represents a getter and a setter into some data type. Then we generalized the
setter to work with functions (using `over`

). Last we realized that `over`

is
not good enough when we want to do side effects, so we moved to `overIO`

and
finally generalized it to the *van Laarhoven* lens of ```
Functor f => (a -> f a)
-> s -> f s
```

.

So far I've only told you that our new `Lens s a`

can behave like `over`

, `set`

and `view`

, but we need to prove it to really understand why. In order to do
this we'll make use to two `Functor`

instances that come from the `base`

library, namely `Data.Functor.Identity`

and `Control.Applicative.Const`

. Let's
start with the simplest one, that is implementing `over`

with the `Identity`

functor.

`over`

with `Identity`

First of all, here's the implementation of `Identity`

.

newtype Identity a = Identity { runIdentity :: a } instance Functor Identity where fmap f (Identity a) = Identity (f a)

The reason why this is useful is because we can put a value in, let it behave as a functor, and then take the value out.

The final type of `over`

that we're looking for is ```
over :: Lens s a -> (a ->
a) -> s -> s
```

. We can read that as: *Given a lens focusing on an a inside of
an s, and a function from a to a, and an s, I can give you back a
modified s from applying the function to the focus point of the lens.*

over :: Lens s a -> (a -> a) -> s -> s over ln f s = _

If you're on GHC 7.8.x you can copy the exact snippet above and get an error telling you what type is needed in place of

`_`

(this functionality is provided by so called type holes.) Also don't forget that you need to add the type alias for`Lens s a`

and enable the`RankNTypes`

extension as mentioned above.

We'll inline the `Lens`

type synonym, just so that we can see what is really
going on. Don't worry if the type looks scary, it will all make sense in a
short while.

over :: (Functor f => (a -> f a) -> (s -> f s)) -> (a -> a) -> s -> s over ln f s = _

I've added a few parentheses, especially around the `s -> f s`

, to make it
clear as we go along with partial applications. Keep in mind that `Lens`

is
just a function, nothing more.

We only have one function of the type `a -> f a`

available here to pass into
the lens `ln`

, and that is `Identity`

.

over :: Lens s a -> (a -> a) -> s -> s over ln f s = _ (ln Identity)

If you want to play along in GHCi, there's a neat little trick you can do to
interactively play with types. Say that you want to see the type of ```
ln
Identity
```

λ> let ln = undefined :: (Functor f => (a -> f a) -> (s -> f s)) λ> :t ln Identity :: s -> Identity s

The reason why this works is because the `undefined`

can take on any type.
Since we're just trying to make the types align, you won't get an error from
trying to evaluate the `undefined`

, you'll just a type error. This way you can
keep trying to partially apply things to see if the types match as you expect.

Anyway, moving on. We haven't really used our function `f`

yet, and there will
be no more `a`

to apply it to ones we give something to the lens `ln`

. This is
why we need to apply it before we stick in the `Identity`

, or compose it with
the `Identity`

to be specific.

over :: Lens s a -> (a -> a) -> s -> s over ln f s = _ (ln (Identity . f))

Now our current type hole if `(s -> f s) -> s`

, which means we can stick in our
`s`

. To make this syntactically more pleasing we'll replace some parentheses
with `$`

.

over :: Lens s a -> (a -> a) -> s -> s over ln f s = _ $ ln (Identity . f) s

Hang in, we're almost done. The last thing we need do, as our type hole tells
us, is `f s -> s`

, which means we basically need to rip off the functor. This
is easy to do as we're using the `Identity`

functor, so we just apply
`runIdentity`

.

over :: Lens s a -> (a -> a) -> s -> s over ln f s = runIdentity $ ln (Identity . f) s

If you're feeling adventurous, we can rewrite this using point free style.

over :: Lens s a -> (a -> a) -> s -> s over ln f = runIdentity . ln (Identity . f)

`view`

with `Const`

Now let's move on to `view`

, where the type is simply ```
view :: Lens s a -> s ->
a
```

. We can read this as: *Given a lens that focuses on an a inside of an s,
and an s, I can give you an a.*

This part is probably the most magical, since the type of the `Lens s a`

is ```
(a
-> f a) -> s -> f s
```

and we're trying to implement something that's `s -> a`

,
which means we need to have a way to turn the final `f s`

into an `a`

. The key
to this is the `Const`

functor.

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

Let's break this down into steps and first explain how `Const`

works. `Const`

is a wrapper which takes a value, hides it deep inside, and then pretends to be
a functor containing something else, which is why it ignores the function
you're trying to `fmap`

over const. Here's an example:

λ> :t Const "hello" :: Const String b

We've hidden a `"hello"`

string inside a `Const`

, now let's try to apply a
boolean function to it using `fmap`

.

λ> let boolBox = fmap (&& False) (Const "hello") λ> :t boolBox Const [Char] Bool

The `Const`

has taken over to be a type of `Const String Bool`

. If we `fmap`

over a function `Bool -> Double`

we'll get a `Const String Double`

.

λ> :t fmap (\_ -> 1.2 :: Double) boolBox :: Const String Double

The important thing to keep in mind here is that the `Const`

simply ignores the
function we're fmapping and takes on the new type, while keeping our original
`String`

safe. We can extract it back at any time we want, no matter how many
things we've `fmap`

ped.

λ> getConst boolBox "hello" λ> getConst $ fmap (\_ -> 1.2 :: Double) boolBox "hello"

`view`

implementationLet's do this using type holes again.

view :: Lens s a -> s -> a view ln s = _

We can approach this the same way as we did before when implementing `over`

using `Identity`

. First of all, here's the type of `Lens s a`

again in case you
forgot `Functor f => (a -> f a) -> s -> f s`

.

If you squint hard enough you can see that if we somehow pass a function to
`ln`

, we'll get back another function of the type `s -> f s`

, which we can give
our `s`

, and then the only thing remaining is to extract the resulting `a`

out
of the `f s`

. Again the only function that fits here is `Const`

.

view :: Lens s a -> s -> a view ln s = _ $ ln Const

The type of the hole here is `(s -> f s) -> a`

, which means we can apply our
`s`

on the right side as we did with `over`

.

view :: Lens s a -> s -> a view ln s = _ $ ln Const s

Now all we're left with is `f s -> a`

, and because we know that the `f s`

is
actually `Const a s`

we can get back the `a`

using `getConst`

view :: Lens s a -> s -> a view ln s = getConst $ ln Const s

And there you go, we got ourselves a `view`

. I won't be showing how to
implement `set`

step by step, since it can be trivially defined either in terms
of `over`

, which is good enough for us.

set :: Lens s a -> a -> s -> s set ln x = over ln (const x)

In order to use lenses we actually need to have some lenses. As said earlier,
we do not need the `lens`

library to define a new lens, we only need a function
with the type of `Functor f => (a -> f a) -> s -> f s`

. Let's make one!

We'll start by implementing the `_1`

lens, which focuses on a first element of
a pair. The type will be `Lens (a,b) a`

or specifically ```
Functor f => (a -> f
a) -> (a,b) -> f (a,b)
```

, in another words *Given a pair of (a,b) the lens
focuses on the first element of the pair, which is a*.

_1 :: Functor f => (a -> f a) -> (a,b) -> f (a,b) _1 f (x,y) = _

An interesting thing about pure functions in Haskell is that more often than not, there is only one way to implement a function so that it typechecks. We can use the types as we did earlier to guide us while implementing this.

Ok let's get going. We have three values available (via the function
parameters), `f :: a -> f a`

, `x :: a`

and `y :: b`

. The only thing we can do
here is apply `f`

to `x`

.

_1 :: Functor f => (a -> f a) -> (a,b) -> f (a,b) _1 f (x,y) = f x

This will fail to typecheck, since we're trying to return `f a`

instead of ```
f
(a,b)
```

. What else can we do now? We know `f`

is a `Functor`

, which means we can
use `fmap`

. We also know that we need to somehow use `y`

to compose the result.
If you think about this for a while, all we can really do is `fmap`

some
function on the result of `f x`

_1 :: Functor f => (a -> f a) -> (a,b) -> f (a,b) _1 f (x,y) = fmap _ (f x)

The result is that the type of `_`

in this case must be `a -> (a, b)`

. That's
it, we only have one thing of type `b`

, which is `y`

, and the `a`

we can take
just form the parameter passed to the lambda, hence giving us the following.

_1 :: Functor f => (a -> f a) -> (a,b) -> f (a,b) _1 f (x,y) = fmap (\a -> (a, y)) (f x)

Whoa, did we just write an actual lens? I believe we did sir. Let's test things out!

Now that we got ourselves a `view`

and `_1`

lens, let's play!

λ> view _1 (1,2) 1

We can also use `set`

and `over`

to change the value

λ> set _1 3 (1,2) (3,2) λ> over _1 (+3) (1,2) (4,2)

Let's see how to define a lens for the original `User`

and `Project`

types.

data User = User { name :: String, age :: Int } deriving Show data Project = Project { owner :: User } deriving Show

We'll start with a lens for the `User`

's `name`

, which simply has the type
`Lens User String`

. There's no magic here, we'll just follow the same pattern
as we did with the `_1`

lens.

nameLens :: Lens User String nameLens f user = fmap (\newName -> user { name = newName }) (f (name user))

As you can see this is just mechanical work. We can define the other two lenses
for `age`

and `owner`

by simply copy pasting the first one and changing a few
things around.

ageLens :: Lens User Int ageLens f user = fmap (\newAge -> user { age = newAge }) (f (age user)) ownerLens :: Lens Project User ownerLens f project = fmap (\newOwner -> project { owner = newOwner }) (f (owner project))

Because lenses are just functions (remember that `Lens s a`

is just a type
alias) we can compose them using the ordinary function composition `.`

ownerNameLens :: Lens Project String ownerNameLens = ownerLens.nameLens

Let's test this out:

λ> let john = User { name = "John", age = 30 } λ> let p = Project { owner = john } λ> view ownerNameLens p "John" λ> set ownerNameLens "Bob" p Project {owner = User {name = "Bob", age = 30}}

Congratulations to you if you've read this far, you now have a good
understanding of how the basic `Lens s a`

works. This is not the end though,
since lenses are a very large subject and there is a lot of ground to cover.
The followup posts to this one will cover the more general `Lens s t a b`

type,
folds, traversals, prisms, isos, using template haskell to generate lenses, and
much more!

If you're curious especially about the `Lens s t a b`

type and what it means,
it's basically just a small generalization of what we've devleoped here.
Compare the following two:

type Lens' s a = Functor f => (a -> f a) -> s -> f s type Lens s t a b = Functor f => (a -> f b) -> s -> f t

This might look weird at first, but it's not if you apply it to a specific data type, such as:

Lens (Int, String) (Double, String) Int Double (Int -> f Double) -> (Int, String) -> f (Double, String)

It simply allows you to change the type of the underlying structure, but as I said earlier, we'll cover this more in one of the upcoming blog posts.

Subscribe to receive updates and free content from the book. You'll also get a discount when the final version of the book is released.

Give love to your JavaScript applications by tracking their runtime exceptions with Trackets.

- Parsing CSS with Parsec
- Lens Tutorial - Stab & Traversal (Part 2)
- Foldable and Traversable
- Building Monad Transformers - Part 1
- Mutable State in Haskell
- Lens Tutorial - Introduction (part 1)
- Using Phantom Types in Haskell for Extra Safety - Part 2
- Using Phantom Types for Extra Safety
- Evil Mode: How I Switched From VIM to Emacs
- Yesod is Fun