JavaScript 커링(Currying): 함수형 프로그래밍 기법

작성일 :

JavaScript 커링(Currying): 함수형 프로그래밍 기법

JavaScript에서 커링(Currying)은 하나의 함수가 여러 개의 인자를 받는 대신, 하나의 인자를 받은 후 나머지 인자를 받는 새로운 함수를 반환하는 것입니다. 이 기법은 함수형 프로그래밍에서 자주 사용되며, 코드의 재사용성과 가독성을 높이는 데 많은 장점을 제공합니다. 이번 글에서는 커링의 개념, 장점, 그리고 몇 가지 예제를 통해 JavaScript에서 커링을 어떻게 적용할 수 있는지 알아보겠습니다.

커링의 개념

커링은 영어 수학자 Haskell Curry의 이름을 딴 것으로, 다중 인수 함수(Multi-Argument Function)를 연쇄적인 단일 인수 함수로 변환하는 것을 의미합니다. 이를 통해 함수 호출 시 하나의 인수만 전달하고, 나머지 인수들은 나중에 전달할 수 있게 됩니다.

js
function add(a, b) {
  return a + b;
}

const curriedAdd = (a) => (b) => add(a, b);

console.log(curriedAdd(2)(3)); // 5

위 예제에서 add 함수는 두 개의 인수를 받습니다. 그러나 curriedAdd 함수는 먼저 첫 번째 인수 a를 받고, 다시 두 번째 인수 b를 받는 새로운 함수를 반환합니다. 이를 통해 여러 인수를 각각의 호출로 분리할 수 있게 됩니다.

커링의 장점

1. 코드의 재사용성 증가

커링을 통해 특정 인수를 고정한 새로운 함수를 쉽게 생성할 수 있습니다. 이는 다수의 함수에서 공통된 인수를 재사용할 때 매우 유용합니다.

js
const add5 = curriedAdd(5);

console.log(add5(3)); // 8
console.log(add5(10)); // 15

이 예제에서는 curriedAdd(5)를 통해 항상 5를 더하는 새로운 함수를 만들었습니다. 이를 통해 반복적인 코드 작성을 피할 수 있습니다.

2. 함수 조합성 향상

커링은 함수형 프로그래밍의 핵심인 함수 조합성을 크게 향상시킵니다. 하나의 함수 실행 결과를 다른 함수의 입력으로 쉽게 전달할 수 있습니다.

js
const multiply = (a, b) => a * b;
const curriedMultiply = (a) => (b) => multiply(a, b);

const multiplyBy2 = curriedMultiply(2);
const addAndMultiply = (a, b) => multiplyBy2(curriedAdd(a)(b));

console.log(addAndMultiply(2, 3)); // 10

위 예제는 curriedAddcurriedMultiply를 사용하여 각기 다른 연산을 쉽게 조합하는 예를 보여줍니다.

3. 소프트웨어 설계의 유연성 증가

커링은 복잡한 소프트웨어 시스템에서 함수의 구성을 더 유연하게 만듭니다. 특히, 다단계 파라미터를 처리할 때 유용하게 사용할 수 있습니다.

js
const fetchData = (url) => (params) => (callback) => {
  const query = Object.keys(params).map(k => `${k}=${params[k]}`).join('&');
  fetch(`${url}?${query}`)
    .then(response => response.json())
    .then(data => callback(null, data))
    .catch(err => callback(err));
};

const fetchGitHubAPI = fetchData('https://api.github.com');
const fetchUser = fetchGitHubAPI({ per_page: 1 });

fetchUser((err, data) => {
  if (err) {
    console.error(err);
  } else {
    console.log(data);
  }
});

이 예제에서는 fetchData 함수가 URL, params, 그리고 콜백을 받아 GitHub API 호출을 처리합니다. 이를 통해 코드의 복잡성을 줄이고, 각 단계에서 함수를 유연하게 구성할 수 있습니다.

커링을 구현하는 방법

JavaScript에서 커링을 구현하는 방법에는 여러 가지가 있지만, 가장 기본적인 방법은 함수 반환을 활용하는 것입니다. 이것은 함수가 다른 함수를 반환하여 각 인수에 대해 독립적인 호출을 가능하게 합니다.

js
const curry = (fn) => {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function (...nextArgs) {
        return curried.apply(this, args.concat(nextArgs));
      };
    }
  };
};

const curriedAdd = curry((a, b) => a + b);

console.log(curriedAdd(1, 2)); // 3
console.log(curriedAdd(1)(2)); // 3

커링 함수는 내부에서 값을 받아 필요한 인수가 모두 채워질 때까지 새로운 함수를 반환합니다. 이렇게 구현된 커링 함수는 인수 개수가 서로 다른 다양한 호출 방식을 지원합니다.

결론

JavaScript에서 커링은 함수형 프로그래밍의 강력한 기법 중 하나로, 코드의 재사용성과 가독성을 크게 향상시킵니다. 커링을 사용하면 특정 인수를 고정한 새로운 함수를 쉽게 생성하고, 함수 조합성을 향상시키며, 복잡한 소프트웨어 설계에서 유연성을 높일 수 있습니다. 실제 프로젝트에서 이 기법을 활용한다면 더 깔끔하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.