lottie
Seungjun's blog
blog
Currying

커링이란?

  다중 인수 (혹은 여러 인수의 튜플)을 갖는 함수를 단일 인수를 갖는 함수들의 함수열로 바꾸는 것을 말한다.

커링은 함수형 프로그래밍을 사용하는 이유와 일치하는데 부수효과를 최대한으로 줄이고, 동일한 입력이 들어가면 동일한 출력이 나오게 하여 가독성과 유지보수를 용이하게 하기 위해 사용되어진다.


*JS의 경우 클래스를 이용한 객체지향뿐만 아니라, 프로토타입 기반의 객체지향, 함수형 프로그래밍까지 가능한 멀티 패러다임 언어이다.



커링 예제

1. 일반적 커링

// 커링 변환을 하는 curry(f) 함수 (일반함수 ver)
function curry(f) {
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}

// 커링 변환을 하는 curry(f) 함수 (화살표함수 ver)
const curry = f => a => b => f(a, b);

// f에 전달된 함수
const sum = (a, b) => a + b;

const curriedSum = curry(sum);

console.log(curriedSum(1)(2)); // 3

위 함수는 다음의 순서로 동작 됩니다.

  • curry(func)의 반환 값은 function(a) 형태입니다.

  • curriedSum(1) 과 같은 함수가 호출되었을 때, 1은 렉시컬 환경에 저장이 되고 function(b)가 반환됩니다.

  • 반환된 function(b) 함수가 2를 인수로 호출됩니다. 반환 값이 원래의 sum으로 넘겨져서 호출됩니다.

  • 최종적으로 sum(1, 2) 가 호출되어 1 + 2인 3이 반환됩니다.


2. 객체 데이터를 가져오는 커링

// 커링을 적용하지 않은 코드

const todos = [
  { id: 3, content: 'HTML', completed: false },
  { id: 2, content: 'CSS', completed: true },
  { id: 1, content: 'Javascript', completed: false }
];

const getTodosIdArr = todos => todos.map(todo => todo.id);
const getTodosContentArr = todos => todos.map(todo => todo.content);
const getTodosCompletedArr = todos => todos.map(todo => todo.completed);

console.log(getTodosIdArr(todos)); // [ 3, 2, 1 ]
console.log(getTodosContentArr(todos)); // [ 'HTML', 'CSS', 'Javascript' ]
console.log(getTodosCompletedArr(todos)); // [ false, true, false ]

일반적인 경우 코드를 작성하면 위와 같이 작성하게 됩니다. 여기에 커링을 적용하면 아래와 같이 코드를 작성할 수 있습니다.

// 커링을 적용한 코드

const todos = [
  { id: 3, content: 'HTML', completed: false },
  { id: 2, content: 'CSS', completed: true },
  { id: 1, content: 'Javascript', completed: false }
];

const get = property => object => object[property];

const getId = get('id');
const getContent = get('content');
const getCompleted = get('completed');

const getTodosIdArr = todos => todos.map(getId);
const getTodosContentArr = todos => todos.map(getContent);
const getTodosCompletedArr = todos => todos.map(getCompleted);

console.log(getTodosIdArr(todos)); // [ 3, 2, 1 ]
console.log(getTodosContentArr(todos)); // [ 'HTML', 'CSS', 'Javascript' ]
console.log(getTodosCompletedArr(todos)); // [ false, true, false ]

커링을 사용하는 경우 인자의 순서는 중요한데, 앞에 존재하는 인자일 수록 변동가능성이 적고 뒤에 있는 인자일 수록 변동가능성이 높기 때문에 이 순서를 고려하여 코드를 설계하는 것이 중요하다고 합니다.


커링의 용도

   코드의 양이 많아지게되면 오류가 발생하였을 때 디버깅 과정이 매우 어렵다. 또한 여러 함수가 존재하거나, 추상화가 큰 함수가 존재하는 경우 함수 내부적으로 여러 일을 처리 할 가능성이 높기 때문에 함수 내부의 코드의 복잡도가 증가하여 함수의 기능을 파악하는데 오랜 시간이 소모된다.

이런 경우 함수형 프로그래밍과 커링 함수는 가독성을 높이고 함수의 작동방식을 명확하게 하여 유지보수를 하는데에 있어서 많은 도움준다.