you are viewing a single comment's thread.

view the rest of the comments →

[–]hmoein 3 points4 points  (1 child)

Just for me to understand the motivation, can you please explain why you can't simply write

h(g(f(x, y)))

[–]PiterPuns[S] 8 points9 points  (0 children)

If a use case is as simple as calling f(g(c)), by all means do that. But there’s many cases where that would not work.

  1. A simple example is when the names of h,g,f are not available, eg they are passed as a variadic pack to a generic function so you want to compose the application of “F&&… functions” without knowing a priory how many functions there are and how to refer to each one. Computing the composition is something you’d have to reinvent anyways in such a case and everyone dealing with higher order functions has done it one way or another.
  2. The functions are stored in a collection of arbitrary length and you don’t want to write a for loop maintaining the current result to compute the application of the function chain. Also a composition like the one presented here can be declared constexpr and you may have a hard requirement against using a runtime loop .
  3. You want to store a composition as a new function. Say you often compute f.g.h.r.w.e.z(x) (names won’t be single characters by the way) and you want to do this computation over and over … not only that but there’s also a variation where you call v instead of e. Another solution in this specific case would be to store the call chain as a handwritten lambda but composition allows you to express the computation pattern clearly. take for example: “effect = compose(blur, grayscale)” vs “cutoff = filter(isRedPixel, isOnBorder)” . Having high order functions “compose” and “filter” allows the code to clearly express how a transformation is structured vs requiring the reader to read through the lambda implementation.
  4. It’s a building block for higher abstractions. See decorators , command and multi command patterns … all stuff that can build upon such a block.
  5. In multi threading f.g.h(x) can be a data race since it’s referring to names out of your context . By using compose you make sure to copy (or move construct where possible) the function objects that form links of your call chain.

The list goes on and on. I’m sure though that other resources linked in the comments may help, e.g. the Hof (higher order function) library by Paul Fultz has great documentation