Skip to content

Instantly share code, notes, and snippets.

@scott-christopher
Created June 18, 2015 01:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scott-christopher/a80af9be36f47901fb50 to your computer and use it in GitHub Desktop.
Save scott-christopher/a80af9be36f47901fb50 to your computer and use it in GitHub Desktop.
Dynamic dispatch objects for Ramda
var _isTransformer = require('./src/internal/_isTransformer');
var _xmap = require('./src/internal/_xmap');
var R = require('./dist/ramda');
/**
* This is an example of separating Ramda's current dynamic dispatching
* into external objects that can be applied explicitly.
*
* n.b. `relationsWith` and `mergeWith` are only included to support
* `dispatchOver` and are likely to be far from optimal.
*/
/**
* Given two lists, will produce a 3-element array containing the difference,
* intersection and complement of the two lists, respectively. The provided
* function is used to compare values of each set for equality.
*
* relationsWith :: ((a, a) -> Boolean) -> [a] -> [a] -> [[a],[a],[a]]
*/
var relationsWith = R.curryN(3, function relationsWith(fn, list1, list2) {
function _relationsWith(xs, l, i, r) {
var idx, x;
if (xs.length === 0) {
return [l, i, r];
} else if (r.length === 0) {
return [R.concat(xs, l), i, r];
} else {
x = xs[0];
idx = R.findIndex(R.partial(fn, x), r);
if (idx >= 0) {
return _relationsWith(
R.tail(xs),
l,
R.append(x, i),
r.slice(0, idx).concat(r.slice(idx + 1))
);
} else {
return _relationsWith(R.tail(xs), R.append(x, l), i, r);
}
}
}
return _relationsWith(list1, [], [], list2);
});
/**
* Merges two objects. When a key exists in both objects, their values
* will be passed to the given function to determine the merged value.
*
* mergeWith :: ((a,a) -> a) -> {a} -> {a} -> {a}
*/
var mergeWith = R.curryN(3, function mergeWith(fn, obj1, obj2) {
var k1 = R.toPairs(obj1),
k2 = R.toPairs(obj2),
lir = relationsWith(R.useWith(R.equals, R.head, R.head), k1, k2),
lr = R.concat(lir[0], lir[2]),
i = R.map(function (pair) {
var k = pair[0],
propK = R.prop(k),
trans = R.useWith(fn, propK, propK);
return [k, trans(obj1, obj2)];
}, lir[1]);
return R.fromPairs(R.concat(lr, i));
});
/**
* When given an object of conditional dispatch pairs and an object
* containing methods, this function will produce a new object
* containing all methods of the original, however replacing those
* whose keys exist in the dispatch object with a function that
* will call the dispatch function, if the dispatch condition is
* satisfied.
*
* @see R.cond
* @see R.ifElse
*
* Conditional :: [(*... -> Boolean), (*... -> *)]
* dispatchOver :: {Conditional} -> {*... -> *} -> {*... -> *}
*/
var dispatchOver = R.curryN(2, function dispatchOver(dispatches, obj) {
return mergeWith(function (ramdaFn, dispatchPair) {
return R.ifElse(dispatchPair[0], dispatchPair[1], ramdaFn);
}, obj, dispatches);
});
/////// DISPATCH OBJECTS
var transducerDispatches = {
map: [
R.pipe(R.nthArg(1), _isTransformer),
// just `_xmap` with logging for demonstration
function(fn, x) {
console.log('-> xmap')
return _xmap(fn, x);
}
]
};
var fantasyDispatches = {
map: [
R.pipe(R.nthArg(1), R.has('map')),
// just `invoker(1, 'map')` with logging for demonstration
function(fn, obj) {
console.log('-> fmap');
return obj.map(fn);
}
]
};
/////// EXAMPLE
var _R = R.pipe(
dispatchOver(transducerDispatches),
dispatchOver(fantasyDispatches)
)(R);
console.log(_R.into([], _R.map(_R.multiply(2)), [1, 2, 3, 4, 5]));
// -> xmap
// [ 2, 4, 6, 8, 10 ]
console.log(_R.map(_R.multiply(2), { map: function(fn) { return fn(21); }}));
// -> fmap
// 42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment