노트

커링

Currying

CS#js · 연결된 개념 2개

쉽게 말하면

커링은 인수를 한꺼번에 받던 함수를 키오스크처럼 한 칸씩 묻는 함수로 바꾸는 거예요. 메뉴까지 고른 화면을 저장해 두면, 다음엔 사이즈만 골라 같은 메뉴를 바로 주문할 수 있죠.

비유의 한계 앞 칸을 미리 채워 둔 함수를 만드는 일 자체는 부분 적용이라는 별개 기법이에요. 커링은 함수를 한 칸씩 받는 모양으로 바꾸기만 하고, 원래 함수를 호출하지는 않아요.

커링(Currying)은 인수 여러 개를 받는 함수 f(a, b, c)를 인수 하나씩 받는 함수의 사슬 f(a)(b)(c)로 바꾸는 기법이다. 바꾸기만 하고 원래 함수를 호출하지는 않는다. 이름은 해스컬 커리(Haskell Curry)에서 왔다.

const add3 = (a, b, c) => a + b + c
const curried = (a) => (b) => (c) => add3(a, b, c)
 
curried(1)(2)(3)          // 6
const add1 = curried(1)   // b와 c를 차례로 기다리는 함수
add1(2)(3)                // 6

앞쪽 인수만 넘겨 둔 함수에 이름을 붙여 재사용할 수 있다. 예를 들어 log(date)(level)(message) 모양이면 log(new Date())로 "지금 시각 로그" 함수를 만들어 둔다. 인수 하나짜리 함수가 되면 함수 합성의 pipe·compose에 끼우기도 쉽다.

부분 적용(Partial Application)과 다른 점

부분 적용은 인수 일부를 미리 고정해 나머지 인수를 받는 새 함수를 만드는 것이다. 둘은 자주 섞여 쓰이지만, 부분 적용된 함수는 나머지 인수를 받으면 바로 결과를 돌려준다. 커링된 함수는 인수를 다 받을 때까지 사슬의 다음 함수를 돌려준다. 이 차이는 인수가 셋 이상일 때 드러난다.

const addOne = add3.bind(null, 1)  // 부분 적용: 첫 인수를 1로 고정
addOne(2, 3)                       // 6, 바로 결과
curried(1)(2)                      // 아직 함수: c를 기다린다
  • 자바스크립트에서는 Function.prototype.bind로 부분 적용을 할 수 있다. 첫 인수는 this이고, 그 뒤에 넘긴 값이 앞쪽 인수로 고정된다
  • lodash의 _.curry 같은 실용 구현은 f(1, 2)처럼 한꺼번에 불러도, f(1)(2)처럼 하나씩 불러도 되는 래퍼를 돌려준다. 인수를 하나씩만 받는 엄밀한 커링보다 너그러운 형태다
  • 커링된 함수는 앞서 받은 인수를 클로저(Closure)로 기억해 둔다. 함수를 값으로 넘기는 패턴은 콜백과도 이어진다

출처: Wikipedia - Currying · Contrast with partial function application · javascript.info - Currying · MDN - Function.prototype.bind: Partially applied functions

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 재귀

    함수가 자기 자신을 다시 호출해 문제를 푸는 방식. 같은 함수를 점점 작은 입력으로 부르다가 더 나눌 필요가 없는 지점(기저 조건, Base Case)에서 멈춘다.

  • Promise continuation

    continuation은 "프로그램의 나머지 계산"을 값처럼 다루는 개념이다. JavaScript에서는 Promise가 settle된 뒤 이어서 실행될 코드를 가리킨다. await 다음 줄부터 함수 끝까지가 대표적인 continuation이다.

  • 명령-질의 분리

    함수를 값을 돌려주는 질의(query)와 상태를 바꾸는 명령(command) 중 하나로만 만들라는 원칙. 질의 함수는 겉으로 관찰되는 부수 효과(Side Effect)가 없어야 한다.

  • 함수 추출하기

    코드 조각에 목적을 드러내는 이름을 붙여 독립된 함수로 빼는 리팩터링. "어떻게"와 "무엇을"을 분리한다. 반대 방향인 함수 인라인하기(Inline Function)는 본문이 이름만큼 명확한 함수를 호출부로 다시 녹인다.

  • 임시 변수를 질의 함수로 바꾸기

    계산 결과를 담아 두던 임시 변수를 그 값을 돌려주는 함수로 바꾸는 리팩터링. 긴 함수를 쪼개기 전 단계로 특히 쓸모 있다.

보기 옵션