こちらの記事の reduceRight() を使った compose() の定義は、関数に値を適用した結果の値をaccとして受け渡すという使い方をしていると思います。
しかし、合成された関数もまた関数であり、それも値としてaccで受け渡すことができるという発想をすれば、reduce() に compose2() をそのまま渡すという選択肢も出てきます。
compose2()を整数の加算 + と対比してみると、初期値 0 の代わりになるものが何か考えれば良いわけです。
[1,2,3].reduce((a,b)=>a+b, 0); // -> 6
[add1, add2, add3].reduce(compose2, ???); // -> add6
0 はどのような整数と加算しても値の変わらない性質があるため reduce() の初期値に選ばれています。
N + 0 == N
同じようにどんな関数と合成しても結果が変わらない関数があればそれを初期値として使えます
compose2(f, ZERO) == f
答えは「引数をそのまま返す関数」です。
このような関数を一般的に恒等関数 id と呼ぶようです。(数学では「恒等写像(identity mapping)」)
const id = (x) => x;
結論として、 compose2() と id() を使えば、任意の数の関数を合成する関数 compose() は以下のように書くとこができます。
const id = (x) => x;
const compose2 = (f, g) => (x) => f(g(x));
const compose = (...fs) => fs.reduce(compose2, id);
ちなみに、このcomposeが実際に役に立った場面について書いた過去の記事はこちらです。
関数合成Composeが初めて役に立った話