Skip to content

Instantly share code, notes, and snippets.

@drejohnson
Forked from branneman/fp-lenses.js
Created May 24, 2018 04:45
Show Gist options
  • Save drejohnson/b9d07b42da294ddf14d755a63165e61a to your computer and use it in GitHub Desktop.
Save drejohnson/b9d07b42da294ddf14d755a63165e61a to your computer and use it in GitHub Desktop.
JavaScript: Lenses (Functional Programming)
// FP Lenses
const lens = get => set => ({ get, set });
const view = lens => obj => lens.get(obj);
const set = lens => val => obj => lens.set(val)(obj);
const over = lens => fn => obj => set(lens)(fn(view(lens)(obj)))(obj);
const lensProp = key => lens(prop(key))(assoc(key));
// Generic FP utils
const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));
const map = fn => list => list.map(fn);
const filter = fn => list => list.filter(fn);
const lt = left => right => left < right;
const add = left => right => left + right;
const upper = str => str.toUpperCase();
const prop = key => obj => obj[key];
const assoc = key => val => obj => { obj[key] = val; return obj; };
/**
* Example usage: Object
*/
const amountLens = lens(prop('amount'))(assoc('amount'));
over(amountLens)(add(5))({ x: 1, amount: 10 });
//=> { x: 1, amount: 15 }
/**
* Example usage: Array
*/
const headLens = lens(prop(0))(assoc(0));
over(headLens)(upper)(['first', 'second']);
//=> [ 'FIRST', 'second' ]
/**
* Example usage: Chaining
*/
const moneyLens = lensProp('money');
const data = [{ money: 42 }, { money: 1024 }, { money: 1337 }];
compose(
map(over(moneyLens)(add('€ '))),
filter(compose(lt(100), view(moneyLens)))
)(data);
//=> [ { money: '€ 1024' }, { money: '€ 1337' } ]
/**
* Example usage: Composition
*/
const article = { title: 'FP ftw!', comments: [{ t: 'boo!' }, { t: 'yay!' }] };
over(lensProp('comments'))(map(over(lensProp('t'))(upper)))(article);
//=> { title: 'FP ftw!', comments: [{ t: 'BOO!' }, { t: 'YAY!' }]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment