[자바스크립트] 함수 결합
💡 tl;dr
- 함수 결합(Function Composition)의 정의
- 예시 및 활용
함수 결합이란
- 두 개 이상의 함수를 결합하여 새 함수를 생성하는 프로세스
- 함수를 결합하는 것은 데이터가 흐르기 위해 파이프를 까는 것과 같음
예를 들어, 는 자바스크립트에서 f(g(x))와 같고, 이는 아래처럼 안에서 밖으로 순서대로 계산된다.
함수 결합의 활용
아래처럼 chain으로 구성된 간단한 코드가 있다.
1 | const toSlug = input => encodeURIComponent( |
이를 함수 결합 형태로 다음과 같이 바꿀 수 있다.
1 | const toSlug = input => encodeURIComponent( |
첫 함수보다 가독성이 떨어져 보이지만, 결합의 방향성은 확연히 보인다.
.reduceRight()
Javascript에는 이를 개선할 수 있는 Array 메서드 .reduce()가 있다.
그러나 .reduce()는 값의 전달 방향이 (왼쪽에서 오른쪽)으로, 예제 toSlug의 형태와는 정 반대의 방향성을 보인다. 이때 사용할 수 있는 함수가 .reduceRight()다. .reduce()와 마찬가지로 reducer 함수와 초기값 x를 사용하고, 배열 함수를 (오른쪽에서 왼쪽)으로 반복하며 누적된 값(v)에 차례로 적용한다.
1 | const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x); |
이를 적용하면 중첩 없이 위 함수 결합을 다시 작성할 수 있다.
1 | const toSlug = compose( |
.reduce()
마찬가지로 .reduce()를 사용하면 (왼쪽에서 오른쪽)으로 순서대로 적용되는 함수의 흐름을 구현할 수 있다. 이를 pipe라고 표현한다.
1 | const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x); |
사용 방법 또한 앞선 compose 함수와 똑같다. 단지 방향성이 바뀌었을 뿐이다.
이를 적용하여 toSlug를 다음과 같이 수정할 수 있다.
1 | const toSlug = pipe( |
함수의 진행 방향이 정확히 반대가 되었다.
trace
데이터가 흐르는 파이프를 구현해놨다면, 이를 검증할 수 있는 trace를 사용할 수 있다.
trace란 파이프 사이사이에서 데이터의 흐름이 올바른지 확인할 수 있는 전략으로, 일반적으로 다음과 같이 구현한다.
1 | const trace = curry((label, x) => { |
사용 방법은 다음과 같다.
1 | const toSlug = pipe( |
tap
tap이란 파이프를 통해 흐르는 데이터에 몇 가지 작업을 수행할 수 있도록하는 기법으로, trace()는 일반적인 tap()의 한 형태일 뿐이다.
다음과 같이 tap()을 작성할 수 있다.
1 | const tap = curry((fn, x) => { |
이제 tap을 이용해 trace를 구현할 수 있다.
1 | const trace = label => { |
이러한 예제들을 통해 함수형 프로그래밍이 무엇인지, 어떻게 함수 결합을 활용하여 더 적은 boilerplate로 더 읽기 쉬운 프로그램을 작성하는지 이해할 수 있다.
참고
해당 글은 Master the JavaScript Interview: What is Function Composition?을 번역 및 수정한 글입니다.
[자바스크립트] 함수 결합
![[자바스크립트] 함수 결합](/img/javascript.gif)
![[스프링] 자바 스프링 시작하기](/img/thumbnail/thumb_spring.png)
![[운영체제] 멀티스레드의 문제점](/img/thumbnail/thumb_os.png)
![[자료구조] 스택(Stack)과 힙(Heap)](/img/thumbnail/thumb_ds.jpg)
![[SWEA] 프로세서 연결하기](/img/thumbnail/thumb_swea.png)
![[백준] 주사위 굴리기](/img/thumbnail/thumb_baekjoon.jpg)