함수 합성(Function Composition)은 한 함수의 출력을 다음 함수의 입력으로 넘기는 식으로 여러 함수를 하나로 묶는 방법이다. 마지막 함수의 출력이 합성된 함수의 결과가 된다.
compose와 pipe
compose(f, g)(x)는f(g(x))다. 수학의 합성처럼 오른쪽 함수부터 실행한다pipe(f, g)(x)는g(f(x))다. 적은 순서대로 실행해서 읽는 순서와 실행 순서가 같다
reduce는 배열을 왼쪽부터, reduceRight는 오른쪽부터 접는다. 둘 다 입력값 x를 누적값으로 시작해, 함수마다 결과를 다음 함수에 넘긴다.
const compose = (...fns) => (x) => fns.reduceRight((acc, fn) => fn(acc), x)
const pipe = (...fns) => (x) => fns.reduce((acc, fn) => fn(acc), x)
const inc = (n) => n + 1
const double = (n) => n * 2
compose(double, inc)(3) // 8: inc 먼저(4) → double(8)
pipe(double, inc)(3) // 7: double 먼저(6) → inc(7)쓸 때 알아 둘 점
- 이어 붙이려면 각 함수가 인수 하나를 받아 값 하나를 돌려주는 편이 좋다. 인수가 여럿인 함수는 커링이나 부분 적용으로 인수 하나짜리로 만든 뒤 끼운다
- 함수가 Promise를 돌려준다면 시작값을
Promise.resolve(x)로 두고fn(acc)대신acc.then(fn)으로 이어, 앞 작업이 끝난 뒤 다음 작업을 실행하게 할 수 있다 - 배열 메서드를 사슬로 이어 반복문을 대신하는 것은 컬렉션 파이프라인이다. 객체 설계에서 말하는 상속보다 합성의 합성은 객체를 조합하는 이야기로, 함수 합성과는 다르다
출처: MDN - Array.prototype.reduceRight: Defining composable functions · MDN - Array.prototype.reduce: Function sequential piping · Running promises in sequence