🔁 Ramda 기초 다지기: R.compose — 오른쪽에서 왼쪽으로 흐르는 함수 조합
함수형 프로그래밍의 강력한 매력 중 하나는 작은 함수를 조합해 큰 동작을 만드는 능력입니다.
Ramda에서는 이 함수 조합을 위해 R.pipe와 R.compose라는 두 가지 툴을 제공합니다.
이전 포스트에서는 R.pipe로 왼쪽에서 오른쪽으로 함수들을 이어 붙였죠.
이번에는 R.compose를 통해 오른쪽에서 왼쪽으로 데이터를 흐르게 하는 방법을 배워봅니다.
🧠 Topic Summary
R.compose란?
R.compose는 여러 함수를 오른쪽에서 왼쪽으로 차례차례 실행해서, 결과값을 만들어내는 함수입니다.
즉, 아래처럼 f3(f2(f1(value)))의 형태로 실행됩니다:
const composedFn = R.compose(f3, f2, f1);
composedFn('data'); // 실행 순서: f1 → f2 → f3
이것은 수학에서 함수 합성 f(g(h(x)))의 형태와 정확히 같으며, 코드 흐름을 수학적 추론처럼 표현하고 싶을 때 유용합니다.
🔍
pipe vs compose
| 특징 | R.pipe | R.compose |
|---|---|---|
| 실행 방향 | 왼쪽 → 오른쪽 | 오른쪽 → 왼쪽 |
| 읽기 방식 | 일반 문장 흐름과 유사 | 수학 함수 합성과 유사 |
| 예시 | pipe(f1, f2, f3)(x) | compose(f3, f2, f1)(x) |
실제로는 어떤 걸 써도 무방하지만, 읽는 순서나 팀 스타일에 따라 선택하면 됩니다.
🛠 Usage Examples
예제 1: 점수 계산 + 설명 붙이기
import * as R from 'ramda';
const describeScore = R.compose(
(score) => `점수는 ${score}점입니다.`,
R.multiply(10), // 10배
R.add(5) // 5 더하기
);
describeScore(7); // "점수는 120점입니다."
// 흐름: 7 → 12 → 120 → 텍스트로 변환설명: 7이라는 숫자에 먼저 5를 더하고(R.add(5)), 그 결과에 10을 곱한 다음, 최종 숫자에 설명 문구를 붙였습니다.
예제 2: URL 정리하기
const cleanUrl = R.compose(
R.toLower, // 모두 소문자로
R.replace(/^https?:\/\//, ''), // http:// 또는 https:// 제거
R.trim // 앞뒤 공백 제거
);
cleanUrl(' https://Example.COM/page '); // 'example.com/page'설명: 사용자가 입력한 URL에서 프로토콜(http://, https://)과 공백을 제거하고, 전부 소문자로 변환해 클린한 URL을 만들었습니다.
예제 3: 사용자 이름 처리 (실전 응용)
const formatUsername = R.compose(
R.toLower,
R.replace(/\s+/g, '_'),
R.prop('name')
);
formatUsername({ id: 1, name: 'John Doe' }); // 'john_doe'설명: 객체에서 name만 추출한 후, 띄어쓰기를 언더스코어로 바꾸고 소문자로 만드는 흐름입니다.
⚠️ Common Pitfalls
1. 순서 헷갈림
compose(f3, f2, f1)은 f1 → f2 → f3 순서로 실행되므로, 초보자에게는 pipe가 더 직관적으로 느껴질 수 있습니다.
2. 여러 인자 함수와 함께 사용 시 에러
compose는 기본적으로 단일 인자 함수 조합을 염두에 둡니다.
두 개 이상의 인자가 필요한 함수는 R.curry, R.partial 등을 함께 사용해야 안정적입니다.
const add = (a, b) => a + b;
const double = x => x * 2;
// 잘못된 예 (add는 두 개의 인자를 받음)
R.compose(double, add)(2); // NaN
// 해결: curry 처리
const curriedAdd = R.curry(add);
R.compose(double, curriedAdd(2))(3); // 103. 디버깅이 어려울 수 있음
실행 순서가 반대이기 때문에, 버그가 발생했을 때 pipe보다 디버깅이 까다로울 수 있습니다.
🧩 Tip: compose는 “마지막 작업부터 생각할 때” 유용하다
예를 들어, “데이터를 보여주기 전에 정리하고, 정리하기 전에 뭔가 계산해야 한다” 같은 상황에서는,
출력 방향부터 생각하는 compose가 더 자연스러운 흐름이 됩니다.
✅ Call to Action
'JAVASCRIPT > Ramda' 카테고리의 다른 글
| [Ramda] 객체 다루기 – `R.prop`, `R.path`, `R.assoc`, `R.evolve` (0) | 2025.05.27 |
|---|---|
| [Ramda] R.map, R.filter, R.reduce로 배열을 함수형 스타일로 다루기 (0) | 2025.05.26 |
| [Ramda] Doc, 함수 목록 (0) | 2025.05.23 |
| [Ramda] R.curry (0) | 2025.05.23 |
| [Ramda] R.pipe (1) | 2025.05.22 |