(b -> b -> c) -> (a -> b) -> a -> a -> c
it almost writes itself.
const on = curry((f, g, x, y) => f(g(x), g(y)));
c
, you only have one place to get it, the f
function. Well, the f
function needs two values of type b
, and you can only get those from the g
function. The g
function needs a value of type a
, and you have two of those: x
, and y
. So you be fair and send both values x
, and y
to g
, then send that to f
, and your function wrote itself.
on(f, identity) == f
you have no other choice for an implementation.
R.ap
, but a variant which is not going to do every permutation, but only apply first function to the first argument in the list, the second function to the second argument in the list, and so on:R.ap([R.multiply(2), R.add(3)], [1,2]); // => [2, 5]
curry
in this case?
zipWith((f, x) => f(x), [R.multiply(2), R.add(3)], [1,2])
const ZipArray = xs => ({
toArray: xs,
map(f) {
return ZipArray(R.map(f, xs));
},
ap({toArray: ys}) {
if (xs.length == 0 || ys.length == 0) {
return ZipArray([]);
} else {
const y = R.head(ys);
const x = R.head(xs);
const yss = R.tail(ys);
const xss = R.tail(xs);
return ZipArray(R.prepend(x(y), ZipArray(xss).ap(ZipArray(yss)).toArray));
}
},
});
R.ap(ZipArray([R.multiply(2), R.add(3)]), ZipArray([1,2])).toArray //=> [2, 5]
const ZipArray = xs => ({
toArray: xs,
map(f) {
return ZipArray(R.map(f, xs));
},
ap({toArray: ys}) {
return ZipArray(R.zipWith((f, x) => f(x), xs, ys));
},
});
R.ap(ZipArray([R.multiply(2), R.add(3)]), ZipArray([1,2])).toArray //=> [2, 5]
R.nthArg
might be cheating a little, depending on your rules of points-free golf :D