f.g.h(x) === f(g(h(x)))
const add1 = x => x + 1;
const double = x => x * 2;
const square = x => x ** 2;
const _ = makeComposable({ add1, double, square });
console.assert(
_.double.add1(1) === double(add1(1))
);
console.assert(
_.double.add1.add1.square(100) === double(add1(add1(square(100))))
);
console.assert(
_.add1.square.add1.double(3) === add1(square(add1(double(3))))
);
- Trap property lookups, and redirect all method lookups to a
Map
of the instrumented functions. This enables chained lookup, e.g.double.square.add1
. - Trap function applications, and pass the result to another pre-bound function. This enables function composition, e.g.
double.square(5)
is reallydouble(square(5))
.
Notational abuse is confusing and this should probably never be used in practice. Additionally, here are some other glaring problems with this implementation:
- Only works with unary functions (i.e. functions of a single argument) right now
- Does absolutely nothing to handle naming collisions with the prototype chain (e.g.
apply
) - One zillion other edge cases I haven't thought about