Conceptly
← 전체 목록
🧩

Currying

함수 활용다인자 함수를 단항 함수 체인으로 바꾸기

커링은 여러 인자를 한꺼번에 받는 함수를, 인자 하나씩 받는 함수들의 연쇄로 바꾸는 기법입니다. f(a, b, c)f(a)(b)(c)처럼 읽게 만드는 방식이라고 보면 됩니다. 이렇게 바꾸면 함수가 매 단계마다 입력 하나만 받게 되어, 함수 합성이나 고차 함수가 기대하는 단항 함수 스타일에 훨씬 잘 맞습니다. 결국 여러 인자 함수의 모양을 조합하기 좋은 형태로 다시 잡아 주는 작업입니다.

아키텍처 다이어그램

🔄 프로세스 다이어그램

점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다

왜 필요한가요?

함수 합성은 보통 입력 하나를 받아 출력 하나를 내는 함수들을 이어 붙일 때 가장 매끄럽습니다. 그런데 실무 함수는 할인율, locale, 옵션 객체처럼 한 번에 여러 인자를 받는 경우가 많죠. 이런 함수를 그대로 pipemap 안에 넣으면 지금 어떤 인자를 주고, 나머지는 언제 줄지 흐름이 어색해집니다. 결국 호출부마다 얇은 래퍼 함수를 덧대게 되고, 비슷한 감싸기 코드가 반복됩니다. 다인자 함수를 단항 함수 흐름에 맞게 정리하는 방법이 필요할 때 커링이 등장합니다.

왜 이런 방식이 등장했나요?

커링은 함수형 프로그래밍보다 더 오래된 개념으로, 수학자 Haskell Curry의 이름에서 왔습니다. 람다 계산과 Haskell, ML 같은 언어에서는 함수가 본질적으로 인자 하나를 받는 형태로 다뤄지고, 여러 인자는 사실 단항 함수의 연쇄로 해석됩니다. 자바스크립트에서는 Ramda, Lodash/fp 같은 라이브러리가 compose, pipe를 중심으로 API를 설계하면서 커링이 널리 퍼졌습니다. 함수형 스타일이 주류 언어로 들어오면서 커링은 이론 지식이 아니라 '합성이 잘 되는 함수 모양'을 만드는 실무 도구가 됐습니다.

내부적으로 어떻게 동작하나요?

커링된 함수는 한 번 호출될 때마다 인자 하나를 받고, 나머지 인자를 기다리는 새 함수를 반환합니다. 예를 들어 add(a, b, c)를 커링하면 첫 호출에서 a를 받고 b를 기다리는 함수를 반환합니다. 그 함수는 다시 b를 받아 c를 기다리는 함수를 반환하고, 마지막 c가 들어오면 비로소 실제 계산을 실행합니다. 각 단계에서 이미 받은 인자는 클로저 안에 보존됩니다. 그래서 add(1)은 '1을 기억한 함수', add(1)(2)는 '1과 2를 기억한 함수'가 됩니다. 커링은 동작을 바꾸는 것이 아니라 함수 시그니처를 단계별 호출 형태로 재구성하는 과정입니다.

코드로 보면

커링으로 단항 함수 체인 만들기

const addVAT = (rate) => (price) => price * (1 + rate);

const addKoreanVAT = addVAT(0.1);   // rate를 먼저 고정
addKoreanVAT(10000);                // 11000

const numbers = [100, 200, 300];
const withVAT = numbers.map(addKoreanVAT);
// [110, 220, 330]

addVAT는 첫 호출에서 세율을 받고, 두 번째 호출에서 실제 가격을 받습니다. rate를 먼저 고정해 만든 addKoreanVAT는 입력 하나만 받는 함수가 되어 map이나 pipe에 바로 넣기 쉬워집니다.

경계와 구분

커링과 부분 적용은 자주 같이 등장하지만 같은 개념은 아닙니다. 커링은 함수의 형태 자체를 여러 인자 → 단항 함수 연쇄로 바꾸는 구조적 변환입니다. 반면 부분 적용은 함수 호출 관점에서 일부 인자를 미리 채워 새 함수를 만드는 사용 패턴입니다. 커링된 함수는 부분 적용하기 쉽지만, 커링되지 않은 함수도 래퍼나 bind를 이용해 부분 적용할 수 있습니다. 즉 커링은 함수 모양의 규칙이고, 부분 적용은 그 모양을 어떻게 활용하느냐의 문제입니다.

트레이드오프

Gain 다인자 함수를 단항 함수 흐름에 맞출 수 있어 합성과 재사용이 쉬워지고, 설정을 단계적으로 주입하는 API를 만들기 좋아집니다. Cost 호출이 fn(a)(b)(c)처럼 여러 단계로 쪼개져 익숙하지 않은 사람에게는 오히려 읽기 어려울 수 있습니다. 어떤 인자를 먼저 받도록 배치할지에 따라 사용성이 크게 달라지므로 인자 순서를 신중히 설계해야 합니다. Decision Scale 같은 함수가 여러 파이프라인에 들어가고, 앞쪽 인자를 자주 고정해 재사용한다면 커링이 강력합니다. 반대로 대부분의 호출이 항상 모든 인자를 한 번에 넘기는 형태라면 커링의 이점이 크지 않을 수 있습니다.

언제 쓰나요?

커링은 검증기, 포맷터, 선택기(selector), API 요청 빌더처럼 '설정은 먼저 고정하고 실제 데이터는 나중에 받는' 함수에서 특히 유용합니다. 함수형 라이브러리들이 커링을 전제로 API를 설계하는 이유도, 작은 함수들을 바로 조합하게 만들기 위해서입니다. 실무에서는 '이 함수가 앞으로 파이프라인의 한 단계로 자주 재사용될까?'를 기준으로 보면 됩니다. 그렇다면 커링으로 입력 하나짜리 함수 형태를 맞춰 두는 편이 이후 조합 비용을 크게 줄여 줍니다.

합성 파이프라인재사용 가능한 검증기포맷터 공장함수형 유틸 라이브러리