Skip to content

Instantly share code, notes, and snippets.

@unscriptable
Last active August 29, 2015 14:13
Show Gist options
  • Save unscriptable/0c3c144a09e0091f37f6 to your computer and use it in GitHub Desktop.
Save unscriptable/0c3c144a09e0091f37f6 to your computer and use it in GitHub Desktop.
Simple (and probably naive) JavaScript Lens implementation
module.exports = Group;
Group.compete = compete;
function Group (equals, compare) {
this.equals = equals;
this.compare = compare;
}
Group.prototype = {
compete: function () {
return compete(this.equals, this.compare);
}
};
/**
* Filter function to determine which of all multiplexed streams
* is currently winning.
* TODO: change this so that multiple streams can be winners, but
* don't use an array of winners. Perhaps inject another function?
*/
function compete (equals, compare) {
var winner;
return function (value) {
var id = identify(value);
if (equals(value, winner) || compare(value, winner) >= 0) {
winner = value;
}
return winner == value;
};
}
module.exports = Lens;
Lens.Object = ObjectLens;
Lens.Array = ArrayLens;
Lens.compose = compose;
Lens.copyObject = copy;
/**
* Lens: given a function that returns a function that maps `a` to
* a "transformed a", it will give us a function that maps `s` to a
* "transformed s".
*/
function ObjectLens (propName) {
return new Lens(get, set);
function get (obj) {
return obj[propName];
}
function set (obj, val) {
var c = copy(obj);
c[propName] = val;
return c;
}
}
function ArrayLens (index) {
return new Lens(get, set);
function get (arr) {
return arr[index];
}
function set (arr, val) {
var c = arr.slice(0);
c[index] = val;
return c;
}
}
function Lens (get, set) {
this.get = get;
this.set = set;
}
Lens.prototype = {
over: function (map) {
var get, set;
get = this.get;
set = this.set;
return function (s) {
set(s, map(get(s)));
return s;
};
},
compose: function (lens) {
return compose(this, lens);
}
};
function compose (lens1, lens2) {
return new Lens(get, set);
function get (a) {
return lens2.get(lens1.get(a));
}
function set (s, a) {
return lens2.set(s, lens1.get(a));
}
}
function copy (o) {
var c = Object.create(Object.getPrototypeOf(o));
var keys = Object.keys(o);
for (var n = 0, len = keys.length; n < len; n++) {
c[n] = o[n];
}
return c;
}
var most = require('most');
var Lens = require('./Lens');
var Group = require('./Group');
var sampleEvent = {
pixelData: { r: 72, g: 27, b: 135 },
coords: { x: 32, y: 7 }
};
var streams = [];
var bundle = most.merge(streams);
var pixelLens = new Lens.Object('pixelData');
var coordsLens = new Lens.Object('coords');
var brightestPixel = Group.compete(sameSource, pixelCompare);
bundle.filter(brightestPixel)
.forEach(console.log.bind(console));
function pixelCompare (s1, s2) {
// this doesn't seem like the intended use case for lenses :)
var p1 = pixelLens.get(s1);
var p2 = pixelLens.get(s2);
return intensity(p1.r, p1.g, p1.b) - intensity(p2.r, p2.g, p2.b);
}
function sameSource (s1, s2) {
var c1 = coordsLens.get(s1);
var c2 = coordsLens.get(s2);
return sameCoords(c1, c2);
}
function intensity (r, g, b) {
// fast, approximate light intensity formula for the human eye
return (r + r + g + g + g + b) / 6 / 256;
}
function sameCoords (c1, c2) {
return c1.x === c2.x && c1.y === c2.y;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment