Output of the inner function becomes the input of the outer function.
Composition requires output-to-input type match.
g:: double -> double
f:: double -> bool
Function f expects a single value, however g returns an array.
g:: int -> [int]
f:: int -> bool
This problem can be solved with monads and Kleisli composition.
f(g(x))
?f(x) = x2 - x - 1
g(x) = x + 1
x
in f
with the definition of g.auto compose = [](auto f, auto g) { return [=](auto x) { return f(g(x)); }; };
auto op = compose(f2, f1);
Unary function composition only.
double fahrenheitToCelsius(double fahr){ return (fahr - 32) * 5.0 / 9.0; }
bool isRoomTemperature(double t){ return (t >= 20.0 && t < 25.0) ? true : false; }
Notice the order, we compose from right to left.
auto op = compose(isRoomTemperature, fahrenheitToCelsius); auto val1 = op(71.9); // returns 1, i.e. room temperature auto val2 = op(50.3); // returns 0, i.e. not room temperature
auto opComposed(double fahr){ return isRoomTemperature(fahreheitToCelsius(fahr)); }
int main() { auto val = opComposed(71.9); // room temperature }
auto vecBool = map(vecTemp, compose(isRoomTemperature, fahrenheitToCelsius));
The composed function can be directly fed into higher-order functions, such as map and filter.
f(g(x))
, then g(f(x))
f(x) = 0.5x - 5
g(x) = 2x + 10
f • g ≠ g • f
The result happened to be the same, because the functions were mutual inverses.
double bmi(double weight, double height){ return weight / height / height; }
bool isOverweight(double bmi){ return (bmi >= 25.0) ? true : false; }
auto compose = [](auto f, auto g) { return [=](auto&& ... x) { return f(g(x...)); }; };
auto op = compose(isOverweight, bmi); auto val1 = op(59.8, 1.7); // returns 0, i.e. false auto val2 = op(73.0, 1.52); // returns 1, i.e. true
(f • g) • h = f • (g • h)
compose(compose(f,g),h)=compose(f,compose(g,h))
(f • g) • h
and f • (g • h)
?
f(x) = x - 2, g(x) = x2, h(x) = 2x
,
Full application produces a value, partial application produces a function that "remembers" values.
Function composition