Lenses

const lens = lensProp('a'); const value = 'baz'; const a = value; const b = view(lens, set(lens, value, store)); console.log(a, b); // 'baz' 'baz'}{ // set(lens, b, set(lens, a, store)) = set(lens, b, store) // If you set a lens value to `a` and then immediately set the lens value to `b`, // it's the same as if you'd just set the value to `b`..const lens = lensProp('a'); const a = 'bar'; const b = 'baz'; const r1 = set(lens, b, set(lens, a, store)); const r2 = set(lens, b, store); console.log(r1, r2); // {a: "baz", b: "bar"} {a: "baz", b: "bar"}}{ // `set(lens, view(lens, store), store)` = `store` // If you get the lens value from the store, and then immediately set that value // back into the store, the value is unchanged..const lens = lensProp('a'); const r1 = set(lens, view(lens, store), store); const r2 = store; console.log(r1, r2); // {a: "foo", b: "bar"} {a: "foo", b: "bar"}}Composing LensesLenses are composable..When you compose lenses, the resulting lens will dive deep into the object, traversing the full object path..Let’s import the more full-featured lensProp from Ramda to demonstrate:import { lensProp } from 'ramda';const lensProps = [ 1 'bar', 'foo',];const lenses = lensProps.map(lensProp);const truth = compose(…lenses);const obj = { foo: { bar: [false, true] }};console.log( truth(obj) // true);That’s great, but there’s more to composition with lenses that we should be aware of..Let’s take a deeper dive.OverIt’s possible to apply a function from a => b in the context of any functor data type..We've already demonstrated that functor mapping is composition..Similarly, we can apply a function to the value of focus in a lens..Typically, that value would be of the same type, so it would be a function from a => a..The lens map operation is commonly called "over" in JavaScript libraries..We can create it like this:// over = (lens, f: a => a, store) => storeconst over = (lens, f, store) => set(lens, f(view(lens, store)), store);const uppercase = x => x.toUpperCase();console.log( over(aLens, uppercase, store) // { a: "FOO", b: "bar" });Setters obey the functor laws:{ // if you map the identity function over a lens // the store is unchanged..const id = x => x; const lens = aLens; const a = over(lens, id, store); const b = store; console.log(a, b);}For the composition example, we’re going to use an auto-curried version of over:import { curry } from 'ramda';const over = curry( (lens, f, store) => set(lens, f(view(lens, store)), store));Now it’s easy to see that lenses under the over operation also obey the functor composition law:{ // over(lens, f) after over(lens g) is the same as // over(lens, compose(f, g)) const lens = aLens; const store = { a: 20 }; const g = n => n + 1; const f = n => n * 2; const a = compose( over(lens, f), over(lens, g) ); const b = over(lens, compose(f, g)); console.log( a(store), // {a: 42} b(store) // {a: 42} );}We’ve barely scratched the surface of lenses here, but it should be enough to get you started.. More details

Leave a Reply