[함수형 프로그래밍] currying 이란 무엇일까?

Yoon Han·2022년 9월 18일
0
post-thumbnail

이번 글에서는 함수형 프로그래밍 패러다임의 기초가 되는 currying 테크닉에 관해 알아보도록 할게요.

❓ Currying

함수형 프로그래밍에서 currying 은 다음과 같습니다.

어떤 함수의 실행을 부분부분으로 쪼개서 실행할 수 있도록 만들어주는 테크닉.

코드로 표현해보자면 다음과 같은 모습이죠.

sum(1, 2, 3) // 일반 함수 
sum(1)(2)(3) // currying 테크닉이 적용된 함수

즉, 함수에 인자를 감질맛나게 하나씩 넘겨주면서 모든 인자가 다 들어온 시점에서야 최종 계산이 이루어지는 방식입니다.


💡 함수 정의하기

curring 을 해주는 curry 함수의 인자와 반환값부터 생각해보겠습니다.
인자로는 함수를 받고, 반환값은 함수 입니다.

이제 curry 함수 구현에 필요한 내용을 정리해볼게요.

curry 함수 정의

  • 인자로는 함수를 하나 받으며, 새로운 함수를 반환한다.
    • 반환되는 함수는 인자를 여러개 받을 수 있다.
  • 반환되는 함수는 2가지 경우를 분기하여 처리한다.
    1. 전달 받은 인자의 갯수가 curry 함수의 인자로 전달된 함수 인자 개수 이상인 경우 -> 즉시 실행
    2. 전달 받은 인자의 갯수가 curry 함수의 인자로 전달된 함수 인자 개수 미만인 경우 -> 함수 평가를 지연시킴.

한 번 코드로 구현하며 더 자세히 살펴보겠습니다.


🛠️ 함수 구현하기

우선 curry 함수의 뼈대만 다음과 같이 잡습니다.
반환되는 함수 curried 는 인자를 여러개 받을 수 있게 ... 연산자를 사용해주었습니다.

function curry(func) {
  return function curried(...args) {
  }
}

이제 curried 함수 내부를 구현할 차례인데요,
curried 함수에 전달된 인자의 개수가 func 함수 인자 개수 이상인 경우를 먼저 살펴보죠.

function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) {
      // 즉시 실행
      return func.apply(this, args)
    }
  }
}

다음으로 curried 함수에 전달된 인자의 갯수가 func 함수 인자 개수 미만인 경우 입니다.

function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) { // Function.prototype.length => 함수의 인자 개수를 반환하는 property
      
      // 즉시 실행
      return func.apply(this, args)
    } else {
      // 새로운 함수를 반환함으로써 함수의 실행을 지연시키고,
      // 추가로 받은 인자 개수만큼 인자 배열에 붙인다.
      return function (...args2) { // 이 익명 함수는 클로져(Closure)이다.
        return curried.apply(this, args.concat(args2))
      }
    }
  }
}

클로져까지 나와서 살짝 머리가 복잡할 수 있습니다.
천천히 흐름을 따라가려 해보시고, 다음 섹션에서 함수를 테스트하며 설명드릴 예시를 보시면 이해가 한층 수월하실거에요.


🧾 함수 테스트하기

숫자를 3개 받아서 모두 더한 값을 반환하는 sum 이라는 함수를 currying 하는 간단한 예제를 보며 curry 함수의 동작 원리를 좀 더 살펴보겠습니다.

const sum = (a, b, c) => a + b + c

const curriedSum = curry(sum) // function curried(...args)
console.log(curriedSum(1)) // function (...args2) { return curried.apply(this, [1].concat(args2)) }
console.log(curriedSum(1)(2)) // function (...args2) { return curried.apply(this, [1, 2].concat(args2)) }
console.log(curriedSum(1)(2)(3)) //  curried.apply(this, [1, 2].concat(3)) => sum.apply(this, [1, 2, 3]) 이므로 "6"

함수를 값으로 다루는 것 + 클로져 패턴이 조합되어서 처음에는 생소하기 때문에 어렵게 느껴질 수 있습니다!
반복적으로 보시면서 익숙해지게되면 처음보단 많이 쉽게 느껴지실 거에요.


Reference

모던 자바스크립트 - 커링

profile
챗바퀴는 도는 삶이 싫은 프론트엔드 엔지니어

0개의 댓글