Conceptly
← 전체 목록
🧩

Currying

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

커링은 여러 인자를 한 번에 받는 함수를, 인자를 하나씩 받는 함수들의 연쇄로 바꾸는 기법입니다. f(a, b, c)f(a)(b)(c)처럼 읽게 만드는 것이 핵심입니다. 이렇게 바꾸면 함수가 각 단계에서 인자 하나만 받으므로, 함수 합성이나 고차 함수가 기대하는 단항 함수 스타일에 자연스럽게 들어갑니다. 여러 인자 함수의 '모양'을 함수형 조합에 맞게 바꾸는 작업이라고 보면 됩니다.

아키텍처 다이어그램

🔄 프로세스 다이어그램

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

왜 필요한가요?

함수 합성은 보통 입력 하나를 받아 출력 하나를 내는 단계들을 이어 붙일 때 가장 단순합니다. 그런데 실무 함수는 할인율, locale, 옵션 객체처럼 여러 인자를 동시에 받는 경우가 많습니다. 이런 함수를 그대로 pipe나 map 안에 넣으면 어느 인자를 지금 주고 어느 인자를 나중에 줄지 구조가 어색해집니다. 결국 호출부마다 작은 래퍼 함수를 덕지덕지 쓰게 되고, 같은 함수를 다른 설정으로 재사용할 때도 매번 비슷한 감싸기 코드가 반복됩니다. 다인자 함수를 단항 함수 흐름에 맞춰 재배열하는 도구가 필요합니다.

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

커링은 함수형 프로그래밍보다 더 오래된 개념으로, 수학자 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를 설계해 작은 함수를 쉽게 합성하도록 돕습니다. 실무에서 중요한 감각은 '이 함수가 앞으로 파이프라인의 한 단계로 재사용될 것인가'입니다. 그렇다면 커링으로 단항 함수 형태를 맞추는 것이 이후 조합 비용을 크게 줄여 줍니다.

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