Why does function composition compose from right to left in Javascript?

To answer the original question: Why does function composition compose from right to left?

  1. So it is traditionally made in mathematics
  2. comp(f)(g)(x) has the same order as f(g(x))
  3. It is trivial to create a reversed or forward composition (see example)

Forward function composition:

const comp = f => g => x => f(g(x));
const flip = f => x => y => f(y)(x);
const flipped = flip(comp);

const inc = a => a + 1;
const sqr = b => b * b;

   comp(sqr)(inc)(2); // 9, since 2 is first put into inc then sqr
flipped(sqr)(inc)(2); // 5, since 2 is first put into sqr then inc

This way of calling functions is called currying, and works like this:

// the original:
comp(sqr)(inc)(2); // 9

// is interpreted by JS as:
( ( ( comp(sqr) ) (inc) ) (2) ); // 9 still (yes, this actually executes!)

// it is even clearer when we separate it into discrete steps:
const compSqr = comp(sqr); // g => x => sqr(g(x))
compSqr(inc)(2);   // 9 still
const compSqrInc = compSqr(inc); // x => sqr(x + 1)
compSqrInc(2);     // 9 still
const compSqrInc2 = compSqrInc(2); // sqr(3)
compSqrInc2;       // 9 still

So functions are composed and interpreted (by the JS interpreter) left to right, while on execution, their values flow through each function from right to left. In short: first outside-in, then inside-out.

But flip has the restriction that a flipped composition can't be combined with itself to form a "higher order composition":

const comp2 = comp(comp)(comp);
const flipped2 = flipped(flipped)(flipped);
const add = x => y => x + y;

   comp2(sqr)(add)(2)(3); // 25
flipped2(sqr)(add)(2)(3); // "x => f(g(x))3" which is nonsense

Conclusion: The right-to-left order is traditional/conventional but not intuitive.


Your question is actually about the order of arguments in a definition of the function composition operator rather than right- or left-associativity. In mathematics, we usually write "f o g" (equivalent to comp(f)(g) in your definition) to mean the function that takes x and returns f(g(x)). Thus "f o (g o h)" and "(f o g) o h" are equivalent and both mean the function that maps each argument x to f(g(h(x))).

That said, we sometimes write f;g (equivalent to compl(f)(g) in your code) to mean the function which maps x to g(f(x)). Thus, both (f;g);h and f;(g;h) mean the function mapping x to h(g(f(x))).

A reference: https://en.wikipedia.org/wiki/Function_composition#Alternative_notations