Skip to content

Instantly share code, notes, and snippets.

@joelburget
Created January 10, 2014 21:51
Show Gist options
  • Save joelburget/8363402 to your computer and use it in GitHub Desktop.
Save joelburget/8363402 to your computer and use it in GitHub Desktop.
js lenses
var getter = function(obj, lens) {
return _(lens).foldl(function(focused, element) {
return focused[element];
}, obj);
};
var modifier = function(obj, lens, mod) {
if (lens.length === 0) {
return mod(obj);
} else {
var monocle = lens[0];
var newObj = _(obj).clone();
newObj[monocle] = modifier(obj[monocle], lens.slice(1), mod);
return newObj;
}
};
// Lens must have length >= 1 or there would be nothing to return
var deleter = function(obj, lens) {
var newObj = _(obj).clone();
if (lens.length === 1) {
delete newObj[lens[0]];
return newObj;
} else {
var newSubObj = deleter(obj[lens[0]], lens.slice(1));
return setter(newObj, lens[0], newSubObj);
}
};
var setter = function(obj, lens, set) {
return modifier(obj, lens, function() { return set; });
};
// Lens must point to a member of an array. We'll insert into that array.
var insertAt = function(obj, lens, toInsert) {
var arrLens = lens.slice(0, -1);
var arr = getter(obj, arrLens).slice(); // slice to copy
var arrIdx = lens[lens.length-1];
arr.splice(arrIdx, 0, toInsert);
return setter(obj, arrLens, arr);
};
var insertBefore = insertAt;
var insertAfter = function(obj, lens, toInsert) {
var newLens = lens.slice();
newLens[newLens.length-1] += 1;
return insertAt(obj, newLens, toInsert);
};
_.mixin({
// > _([1,2,3,4]).scanl(function(l, r) { return l + r; }, 0)
// [1, 3, 6, 10]
scanl: function(obj, iterator, memo, context) {
return _(obj).map(function(value, index, list) {
memo = iterator.call(context, memo, value, index, list);
return memo;
});
},
lensGet: getter,
lensMod: modifier,
lensSet: setter,
lensDel: deleter,
insertAt: insertAt,
insertBefore: insertBefore,
insertAfter: insertAfter
});
// examples
//
// > _({ x: 1, y: 2 }).lensDel(['x'])
// { y: 2 }
//
// > _({ x: 1, y: 2 }).lensSet(['y'], 3)
// { x: 1, y: 3 }
//
// > _({ x: 1, y: 2 }).lensMod(['y'], function(y) { return y + 1; })
// { x: 1, y: 3 }
//
// > _({ x: 1, y: 2 }).lensGet(['x'])
// 1
//
// > _([0, 1, 2]).insertAt([3], 3)
// [0, 1, 2, 3]
//
// > _([0, 1, 2]).insertBefore([0], -1)
// [-1, 0, 1, 2]
//
// > _([0, 1, 2]).insertAfter([2], 3)
// [0, 1, 2, 3]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment