Ross Esmond

Code, Prose, and Mathematics.

a picture of me
Written — Last Updated


A lens is a pair of get and set functions used to read and update components of immutable values. For example, a programmer could read the first item from a list, alter it in some way, and write it back to the list. The get function takes only the target entity as an argument, getFirstItem(list), whereas the set function takes the target entity and the updated component as arguments, setFirstItem(list, item). Taking the original item during a set allows the lens to replace the first item in the list without losing the remaining items. If the read and write involved all of the Information stored withing a value, a get and set could simply be an injective function with its inverse, as with conversion between units. Of course, if the get function only pulls a subset of the information stored within a value, it is not possible for get to be injective, and set cannot be an inverse of get. Lenses may then be thought of as a way to give not injective functions an inverse. Lenses may also be used to protect against changes to the underlying data type, boosting Information Flexibility.

Lens laws

Lenses are designed to mimic a function and its inverse, but without injectivity. To this end, there are three lens laws which should be satisfied to define the lens as “well behaved.” The first is called the get-set law, which says that setting a component which you just read should be a non-operation.

setFirstItem(list, getFirstItem(list)) === list

The second law is called the set-get law, which says that getting a component which you just set should return the set value.

getFirstItem(setFirstItem(list, item)) === item

These two laws are similar to that of bijective, inverse functions.

toCelcius(toFahrenheit(c)) === c
toFahrenheit(toCelcius(f)) === f

Finally, we have the set-set law, which says that setting a component twice should render the first write insignificant.

setFirstItem(setFirstItem(list, A), B) === setFirstItem(list, B)


Aria Beingessner suggested the use of lenses (without explicitely naming them) to allow the Rust compiler to maintain metadata on Pointers whenever the developer updated its Address.