728x90

🔁 Ramda 기초 다지기: R.compose — 오른쪽에서 왼쪽으로 흐르는 함수 조합

함수형 프로그래밍의 강력한 매력 중 하나는 작은 함수를 조합해 큰 동작을 만드는 능력입니다.
Ramda에서는 이 함수 조합을 위해 R.pipeR.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); // 10

3. 디버깅이 어려울 수 있음

실행 순서가 반대이기 때문에, 버그가 발생했을 때 pipe보다 디버깅이 까다로울 수 있습니다.


🧩 Tip: compose는 “마지막 작업부터 생각할 때” 유용하다

예를 들어, “데이터를 보여주기 전에 정리하고, 정리하기 전에 뭔가 계산해야 한다” 같은 상황에서는,

출력 방향부터 생각하는 compose가 더 자연스러운 흐름이 됩니다.


✅ Call to Action

728x90

+ Recent posts