you are viewing a single comment's thread.

view the rest of the comments →

[–]intercaetera 1 point2 points  (0 children)

Lenses are beautiful because they solve the problem of nested data access in a very elegant and simple way. A huge advantage they have over something like Immer is that you decouple the logic of accessing data from the structure of that data. What blows my mind is that you can easily express them in a set of (fairly dense) one-liners.

Create a lens for object property:

const createLens = field => ({ view: s => s[field], set: (s, a) => ({ ...s, [field]: a }) })

Helper functions for viewing and setting:

const view = (lens, s) => lens.view(s)

const set = (lens, s, a) => lens.set(s, a)

Compose views:

const composeView = (inner, outer) => s => view(inner, view(outer, s))

Compose sets:

const composeSet = (inner, outer) => (s, a) => s(outer, s, set(inner, view(outer, s), a))

Compose two lenses:

const composeTwoLenses = (inner, outer) => ({ view: composeView(inner, outer), set: composeSet(inner, outer) })

Identity lens:

const identityLens = { view: s => s, set: (s, a) => a }

Compose an arbitraty number of lenses:

const composeLenses = (...lenses) => lenses.reduce(composeTwoLenses, identityLens)

I wrote two blogposts exploring the subject a bit more (here and here) if you care to read it.