Lenses: The What and How
Tags: javascript, functional, lenses, immutability
Published: 2018-12-12 23:39:32

---
title: Lenses: The What and How
published: true
description: Lenses are directly composable accessors. Read on, to learn how they work, and how you could write your own.
cover_image: https://thepracticaldev.s3.amazonaws.com/i/mlt7ydqaqc5r09rln9ka.jpg
tags: javascript, fp, lenses, immutability
---

In this post, I want to show you what lenses in functional programming are, how you could use them, and most importantly: how you could write your own lenses implementation.

TL;DR
**Lenses are directly composable accessors. Read on, to learn how they work, and how you could write your own.**

_I created a little Notebook on Runkit for you, that contains all examples and a second, alternative implementation. So you could play around with that at any time (before-, while- or after- reading this article). See here:_ https://runkit.com/mister-what/lenses


## Intro

Let's start with a description of a problem. Imagine you have the following data structure, that lists employees by their location and position.

```js
const locations = {
  berlin: {
    employees: {
      staff: {
        list: [
          {
            name: "Wiley Moen",
            phone: "688-031-5608",
            id: "cdfa-f2ae"
          },
          {
            name: "Sydni Keebler",
            phone: "129-526-0289",
            id: "e0ec-e480"
          }
        ]
      },
      managers: {
        list: [
          {
            name: "Cecilia Wisoky",
            phone: "148-188-6725",
            id: "9ebf-5a73"
          }
        ]
      },
      students: {
        list: [
          {
            name: "Kirsten Denesik",
            phone: "938-634-9476",
            id: "c816-2234"
          }
        ]
      }
    }
  },
  paris: {
    employees: {
      staff: {
        list: [
          {
            name: "Lucius Herman",
            phone: "264-660-0107",
            id: "c2fc-55da"
          }
        ]
      },
      managers: {
        list: [
          {
            name: "Miss Rickie Smith",
            phone: "734-742-5829",
            id: "2095-69a7"
          }
        ]
      }
    }
  }
};
```

Accessing data in this structure from different places all over your application gives you a lot of repetition and might lead to hard to find bugs, when the data structure changed (for whatever reason).
So let's explore an alternative approach for this problem: Lenses

## Lenses

Lenses are used for accessing and manipulating data in a safe and immutable way. Well the same is true for accessors (getter & setters) on objects, its not fancy and nothing special. What makes lenses really powerful (and really coool) is that they are directly composable. So what does that mean? If you ever had some maths class in your life, you know, that functions can be composed with each other, i.e. you have ![f: \ X \rightarrow Y,\ g: \ Y \rightarrow Z](http://quicklatex.com/cache3/1c/ql_abe64b3f3052b7b9d13ab6ac23d1da1c_l3.png) then you can define the composition of f with g as ![g \circ f: \ X \rightarrow Z](http://quicklatex.com/cache3/fa/ql_4401cbde8baab9b24245f3bd54640afa_l3.png) and means nothing else than ![(g \circ f)(x) = g(f(x))](http://quicklatex.com/cache3/dd/ql_93a3bfaa93f9f30ed7059eade7abfddd_l3.png).

So how would we express a composition in Javascript? Simply like that:

```js
function compose(g, f) {
    return function(x) {
        return g(f(x));
    }
}

// or with fat-arrow functions:
const compose = (g, f) => x => g(f(x));
```

We could define higher orders of composition in three (or more ways):

```js
// recursive version
const compose = (...fns) => x =>
  fns.length
    ? compose(...fns.slice(0, -1))(
        fns[fns.length - 1](x)
      )
    : x;

// iterative version
const composeItr = (...fns) => x => {
  const functions = Array.from(
    fns
  ).reverse();
  /* `reverse` mutates the array,
  	so we make a shallow copy of the functions array */
  let result = x;
  for (const f of functions) {
    result = f(result);
  }
  return result;
};

// with Array.prototype.reduce
const composeReduce = (...fns) => x =>
  fns.reduceRight(
    (result, f) => f(result),
    x
  );

// use it!
console.log(
  compose(
    x => `Hello ${x}`,
    x => `${x}!`
  )("World")
); // -> "Hello World!"

```

We know now how to compose functions. One thing you may have noticed already, is that function composition works best, when the argument and return value of the composed functions are of the same type.

Let's define a composed getter for the students of a location:

```js
const studentsAtLocation = compose(
    (students = {}) => students.list || [],
    (employees = {}) => employees.students,
    (location = {}) => location.employees
  );

const locationWithName = locationName => (
  locations = {}
) => locations[locationName];

const getBerlinStudents = compose(
  studentsAtLocation,
  locationWithName("berlin")
);

const getParisStudents = compose(
  studentsAtLocation,
  locationWithName("paris")
);

console.log(
  getBerlinStudents(locations)
); // [ { name: 'Kirsten Denesik', ... ]

console.log(
  getParisStudents(locations)
); // []
```
If you are still with me, you might have noticed, that the getter functions are somehow provided in a reverse order. We will resolve this, by using functions that take a getter as argument and return a getter. This pattern (passing a function and returning a function) will allow us to compose basically from getter/setter pairs, by passing a function that takes a value and returns us a getter/setter pair. Let's take a look, how this could look like:

```js
const createComposableGetterSetter = (
  getter, // (1)
  // -- getter(targetData: TargetData): Value
  setter // (4)
  // -- setter(value: Value, targetData: TargetData) => TargetData
) => toGetterAndSetter => targetData => { // (2)
  const getterSetter = toGetterAndSetter(
    getter(targetData)
  ); // (3)
  /**
   * toGetterAndSetter is called with
   * "data" as argument
   * and returns a GetterSetter object:
   * @typedef {
   *  {
   *    get: function(): *,
   *    set: function(newData: *): GetterSetter
   *  }
   * } GetterSetter
   *
   */
  return getterSetter.set(
    setter(
      getterSetter.get(),
      targetData
    )
  ); // (5)
};
```

Even if this is "just" a two-line function body, it takes some time to understand what's going on here, so I'll explain step by step:

1. After calling `createComposableGetterSetter` with a getter and a setter function as arguments, we get back the actutal `composableGetterSetter`.
2. Our `composableGetterSetter` will get a `toGetterAndSetter` function, that takes some data as input and returns an object with a `get` and a `set` method. We return a function, that expects the target data as its only argument.
3. We construct a GetterSetter object by calling **(1)** with the target data from **(2)** and passing the return value to the `toGetterAndSetter` function.
4. We use the GetterSetter objects `set()` method with the return value of calling the setter **(4)** with the value of the constructed GetterSetter object (we call `getterSetter.get()` to simply retrieve this value) and the targetData (we expect, that the setter will return a new version of `targetData` with its focused value set to the return value from `getterSetter.get()`).
5. We return the value (which is again a GetterSetter object) that is returned from `getterSetter.set(...)` in **(5)**.

### toGetterAndSetter

We have now defined our `createComposableGetterSetter` function. We still need to define our `toGetterAndSetter` function, that we will use, to either just get data from the target or set data on the target. Let's define our `toSetAccessors` first:

```js
const toSetAccessors = data => ({
  get: () => data,
  set: newData => toSetAccessors(newData)
});
```

So simple function constructs an object for us, that is used, whenever we want to set data on the target object. Whenever its `set` method is called with new data, it will create a new instance of itself that holds the new data and returns this instance.

Next the `toGetAccessors` function:

```js
const toGetAccessors = data => ({
  get: () => data,
  set() {
    return this;
  }
});
```
A GetAccessor object should only allow to retrieve its data. When trying to set new data, it will simply return its own instance. This makes it impossible to change after creating it.

### Using ComposableGetterSetters (Lenses)

We are now going to create three ComposableGetterSetters -- aka lenses -- to see how they work and what is needed to use them for retrieving values or changing the data (in an immutable way).

#### Creating lenses

We are going to create one lens that focuses on the property "paris", one lens that has focus on the property "employees" and a third one that has focus on the property "students". 
_We will use default values in getters (to avoid exceptions) and object spread to maintain immutability in setters._

```js
const parisLens = createComposableGetterSetter(
  obj => (obj || {}).paris,
  (value, obj) => ({
    ...obj,
    paris: value
  })
);

const employeesLens = createComposableGetterSetter(
  obj => (obj || {}).employees,
  (value, obj) => ({
    ...obj,
    employees: value
  })
);

const studentsLens = createComposableGetterSetter(
  obj => (obj || {}).students,
  (value, obj) => ({
    ...obj,
    students: value
  })
);
```

We notice some repetition here, so let's refactor that:
```js
const lensProp = propName =>
  createComposableGetterSetter(
    obj => (obj || {})[propName],
    (value, obj) => ({
      ...obj,
      [propName]: value
    })
  );

// we can now create lenses for props like this:

const parisLens = lensProp("paris");

const employeesLens = lensProp(
  "employees"
);

const studentsLens = lensProp(
  "students"
);

const listLens = lensProp("list"); // needed to get the list of students

```

We can now start composing (and using) our lenses:

```js
const parisStudentListLens = compose(
  parisLens,
  employeesLens,
  studentsLens,
  listLens
);

const parisStudentList = parisStudentListLens(
  toGetAccessors
)(locations).get();

console.log(parisStudentList);
// -> undefined, since there is no list of students for paris defined.

const locationsWithStudentListForParis = parisStudentListLens(
  _list => toSetAccessors([])
  // ignore current list and replace it with an empty array
)(locations).get();

console.log(
  locationsWithStudentListForParis
);// -> { ..., paris: { employees:{ ..., students: { list: [] } } } }

```

As this would be very verbose to use, let's define some helpers:

```js
const view = (lens, targetData) =>
  lens(toGetAccessors)(
    targetData
  ).get();

const over = (
  lens,
  overFn /* like the `mapf` callback in `Array.prototype.map(mapf)`.
	i.e.: You get a value and return a new value. */,
  targetData
) =>
  lens(data =>
    toSetAccessors(overFn(data))
  )(targetData).get();

const set = (lens, value, targetData) =>
  over(
    lens,
    () =>
      value /* we use `over` with a `overFn` function, 
    	that just returns the value argument */,
    targetData
  );
```

Let's try to use our helpers:

```js
// using get, set, over:

const locationsWithStudentListForParis = set(
  parisStudentListLens,
  [],
  locations
);

const locationsWithOneStudentInParis = over(
  parisStudentListLens,
  (list = []) => [
    ...list,
    { name: "You", setVia: "Lens" }
  ],
  locations
);

const locationsWithTwoStudentInParis = over(
  parisStudentListLens,
  (list = []) => [
    ...list,
    { name: "Me", setVia: "Lens" }
  ],
  locationsWithOneStudentInParis
);

// logging the results:

console.log(
  view(parisStudentListLens, locations)
); // -> undefined

console.log(
  view(
    parisStudentListLens,
    locationsWithStudentListForParis
  )
); // -> []

console.log(
  view(
    parisStudentListLens,
    locationsWithTwoStudentInParis
  )
); // -> [ { name: 'You', setVia: 'Lens' }, { name: 'Me', setVia: 'Lens' } ]

console.log(
  view(
    parisStudentListLens,
    locationsWithOneStudentInParis
  )
); // -> [ { name: 'Me', setVia: 'Lens' } ]

console.log(
  locationsWithTwoStudentInParis
); // -> ...

```

This approach makes upating deeply nested immutable data structures a breeze. To make it even simpler, you could define `lensIndex(index: number)` and `lensPath(path: Array<string|number>)` lens creator helpers. `lensIndex` is then being used to focus on array values. `lensPath` creates a lens that focuses on deeply nested object properties and array indexes, by creating and pre-composing lenses `lensProp` and `lensIndex` lenses for you.

### More areas of application for lenses

Lenses are perfect for conversions between all kinds of values like currencies, temperature, units (metric units to imperial units and vise versa), sanitizing user input, parsing and stringifying JSON and much more.

Enjoy trying and playing around with lenses (don't miss to check out the [Runkit Notebook](https://runkit.com/mister-what/lenses)). If you didn't understand some of my gibberish, please feel free to ask!

I'm happy to answer any questions :)