data/lens

Lenses are a purely functional solution to the issue of accessing and setting fields in deeply nested data structures without special language support. Indeed, most of the symbols exported by this module are either lenses (represented as tables for reflection and introspection reasons) or functions that operate on lenses.

`A` lens is defined as two basic operators:

• `A` function that returns a piece of a data structure given some data structure (a getter, called `view`)
• `A` function that given a function and some data structure, replaces a bit of that data structure with the result of applying that function (a replacer, called `over`).

We will be using, as a running example, two data structures: the list and the struct.

``````> (define list-example (range :from 1 :to 10))
out = '(1 2 3 4 5 6 7 8 9 10)
> (define struct-example (struct :foo "bar" :baz "quux"))
out = (struct "foo" "bar" "baz" "quux")
``````

Lists have two lenses, `head` and `tail`, which correspond to `car` and `cdr`, respectively. To use a lens to zoom into a part of a data structure, we can use the combinator `view`. If we were to give `view` a type, it would be `Lens a b -> a -> b`. It uses the getter defined by the lens to access a bit of a data structure.

``````> (view head list-example)
out = 1
> (view tail list-example)
out = '(2 3 4 5 6 7 8 9 10)
``````

Note that lenses may also be applied directly to values, which equates to using `view`. That is, `(lens x)` is `(view lens x)`.

Of course, if lenses were only used to `view` values, they would not be very useful; What is the point of using `(view head ...)` over just `(car ...)`? Their real use comes from the other function that makes up a lens, `over`. `over` applies a function to a specific bit of a data structure. For example, the `over` implementation for `head` returns a new list with the first element replaced.

``````> (over head succ list-example)
out = '(2 2 3 4 5 6 7 8 9 10)
``````

Notice that `over` doesn’t just return the new head, but the a copy of the existing list with the new head in place.

Again, lenses don’t seem very useful until you learn the other property that they all have in common: composition. Lenses, you see, are like functions: You can take two and `<>` them together, producing a lens that `view`s and modifies (with `over`) a inner piece of the data structure.

For example, by composing `head` and `tail`, you may focus on the second element of a list using `(<> head tail)`, or the tail of the first element of a list (given that element itself is a list itself) using `(<> tail head)`.

``````> (over (<> head tail) succ list-example)
out = '(1 3 3 4 5 6 7 8 9 10)
``````

`(<> &lenses)`

Defined at lib/data/lens.lisp:138:2

Compose, left-associatively, the list of lenses given by `LENSES`.

`(^. val lens)`

Defined at lib/data/lens.lisp:149:2

Use `LENS` to focus on a bit of `VAL`.

`(^= val lens new)`

Defined at lib/data/lens.lisp:161:2

Use `LENS` to replace a bit of `VAL` with `NEW`.

`(^~ val lens f)`

Defined at lib/data/lens.lisp:155:2

Use `LENS` to apply the function `F` over a bit of `VAL`.

`(accumulating f z l)`

Defined at lib/data/lens.lisp:310:2

Transform the lens `L` into a getter which folds the result using the function `F` and the zero element `Z`. For performance reasons, a right fold is performed.

Example:

``````> (view (accumulating + 0 (on :bar))
.       (list { :bar 1 }
.             { :bar 2 }
.             { :baz 3 } ))
out = 3
``````

`(at k)`

Defined at lib/data/lens.lisp:223:2

`A` lens that focuses on the K-th element of a list. `view` is equivalent to `.>`, and `over` is like `.<!`.

Example:

``````> (^. '(1 2 3) (at 2))
out = 2
``````

`(every x ln)`

Defined at lib/data/lens.lisp:326:2

`A` higher-order lens that focuses `LN` on every element of a list that satisfies the perdicate `X`. If `X` is a regular value, it is compared for equality (according to `eql?`) with every list element. If it is a function, it is treated as the predicate.

Example:

``````> (view (every even? it) '(1 2 3 4 5 6))
out = (2 4 6)
> (view (every 'x it) '(1 x 2 x 3 x 4 x))
out = (x x x x)
``````

`(folding f z l)`

Defined at lib/data/lens.lisp:294:2

Transform the (traversing) lens `L` into a getter which folds the result using the function `F` and the zero element `Z`. For performance reasons, a right fold is performed.

Example:

``````> (view (folding + 0 (traversing (on :bar)))
.       (list { :bar 1 }
.             { :bar 2 }
.             { :baz 3 } ))
out = 3
``````

`(getter view)`

Defined at lib/data/lens.lisp:88:2

Define a getting lens using `VIEW` as the accessor.

Lenses built with `getter` can be composed (with `<>`) or used to focus on a value (with `view`).

`(getter? lens)`

Defined at lib/data/lens.lisp:110:2

Check that `LENS` has a defined getter, along with being tagged as a `LENS`. This is essentially a relaxed version of `lens?` in regards to the setter check.

Defined at lib/data/lens.lisp:201:1

`A` lens equivalent to `car`, which `view`s and applies `over` the first element of a list.

Example:

``````> (^. '(1 2 3) head)
out = 1
``````

`it`

Defined at lib/data/lens.lisp:191:1

The simplest lens, not focusing on any subcomponent. In the case of `over`, if the value being focused on is a list, the function is mapped over every element of the list.

`(lens view over)`

Defined at lib/data/lens.lisp:75:2

Define a lens using `VIEW` and `OVER` as the getter and the replacer functions, respectively.

Lenses built with `lens` can be composed (with `<>`), used to focus on a value (with `view`), and replace that value (with `set` or `over`)

`(lens? lens)`

Defined at lib/data/lens.lisp:102:2

Check that is `LENS` a valid lens, that is, has the proper tag, a valid getter and a valid setter.

`(on k)`

Defined at lib/data/lens.lisp:244:2

`A` lens that focuses on the element of a structure that is at the key `K`.

Example:

``````> (^. { :foo "bar" } (on :foo))
out = "bar"
``````

`(on! k)`

Defined at lib/data/lens.lisp:262:2

`A` lens that focuses (and mutates) the element of a structure that is at the key `K`.

Example:

``````> (define foo { :value 1 })
out = {"value" 1}
> (^= foo (on! :value) 5)
out = {"value" 5}
> foo
out = {"value" 5}
``````

`(over l f v)`

Defined at lib/data/lens.lisp:169:2

Flipped synonym for `^~`

`(overl! lens f val)`

Macro defined at lib/data/lens.lisp:183:2

Mutate `VAL` by applying to a bit of it the function `F`, using `LENS`.

`(set l n v)`

Defined at lib/data/lens.lisp:173:2

Flipped synonym for `^=`

`(setl! lens new val)`

Macro defined at lib/data/lens.lisp:177:2

Mutate `VAL` by replacing a bit of it with `NEW`, using `LENS`.

`(setter over)`

Defined at lib/data/lens.lisp:95:2

Define a setting lens using `VIEW` as the accessor.

Lenses built with `setter` can be composed (with `<>`) or used to replace a value (with `over` or `set`).

`(setter? lens)`

Defined at lib/data/lens.lisp:117:2

Check that `LENS` has a defined setter, along with being tagged as a `LENS`. This is essentially a relaxed version of `lens?` in regards to the getter check.

`tail`

Defined at lib/data/lens.lisp:212:1

`A` lens equivalent to `cdr`, which `view`s and applies `over` to all but the first element of a list.

Example:

``````> (^. '(1 2 3) tail)
out = (2 3)
``````

`(traversing l)`

Defined at lib/data/lens.lisp:281:2

`A` lens which maps the lens `L` over every element of a given list.

Example:

``````> (view (traversing (at 3)) '((1 2 3) (4 5 6)))
out = (3 6)
``````

`(view l v)`

Defined at lib/data/lens.lisp:165:2

Flipped synonym for `^.`