커링이란?

커링이란 f(a, b, c) 를 f(a)(b)(c) 와 같이 여러 개의 인수를 단일 프로세스로, 호출 가능한 함수를 다중 프로세스 형태로 변환할 수 있도록 하는 기술이다.

보통 자바스크립트에서 커링되어진 함수는 평소처럼 호출도 하고 만약에 인수들이 충분하지 않을 때는 partial 을 반환한다.

커링은 partial 을 쉽게 적용할 수 있도록 해준다.

커링을 사용하는 이유?

커링 함수를 사용하는 이유는 함수가 여러 개의 인자를 받을 때 특정 인자를 고정할 수 있습니다. 그로 인해 함수의 재사용성을 높일 수 있습니다.

// 커링을 사용한 함수
const currying = a => b => c => a * b * c;
console.log(currying(1)(2)(3)); // 6

// 인수 고정으로 재사용성 높이기
const alwaysMultiple2 = currying(1)(2);
console.log(alwaysMultiple2(3)); // 6

커링 구현

function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) {
      return func.apply(this, args);
    } else {
      return function pass(...args2) {
        return curried.apply(this, args.concat(args2));
      }
    }
  }
}

curry(func) 의 반환값은 curried 라는 래퍼이다. curried 라는 래퍼 안에는 두 개의 if 분기점이 있다.

if 조건을 충족하는 경우 즉 args 를 카운트한 갯수가 전달된 원래 함수 func 의 매개변수 개수와 같거나 크다면, 그대로 func 호출에 args 를 전달한다.

반면 if 조건을 충족하지 못하는 경우 아직 func 이 호출되지 않고 pass 라는 래퍼가 대신 반환된다. pass 래퍼함수가 curried 래퍼를 이전에 입력된 인수와 새로운 인수와 함께 다시 적용한다. 그 다음 새로운 curried 래퍼 호출에 인수가 충분하지 않으면 새로운 pass 래퍼를 반환하거나 최종적으로 func 결과를 반환한다.

커링 사용 예시 1)

function sum(a, b, c) {
  return a + b + c;
}

const curriedSum = curry(sum);

console.log(curriedSum(1, 2, 3)); // 6, 평소처럼 단일 callable 형식으로 호출
console.log(curriedSum(1)(2, 3)); // 6, 첫 번째 인수 커링
console.log(curriedSum(1)(2)(3)); // 6, 모두 커링

sum 함수는 인수가 세 개이므로 sum.length = 3 이다.

 

curriedSum(1)(2)(3) 이 호출되는 과정은 다음과 같다.

1. 첫번째 curriedSum(1) 을 호출할 때 1을 렉시컬 환경에 기억하고 curriedSum(1)이 pass 래퍼를 반환한다.

2. pass 래퍼가 (2)와 함께 호출된다. 이전의 인수인 (1)과 (2)를 연결해 curried(1, 2) 를 함께 호출한다. 인수의 개수는 2개로 아직 3보다 작기 때문에 curried 는 pass 래퍼를 반환한다.

3. pass 래퍼가 다시 (3)과 함께 호출된다. 다음 호출인 pass(3) 이 이전의 인수들인 (1, 2) 를 가져와 (3) 을 연결해 curried(1, 2, 3) 호출을 한다.

4. 인수의 개수는 3개로 sum 함수의 인수 3개와 같기 때문에 if 조건을 충족해 인수를 func 에 전달해 func(1, 2, 3) 호출한 후 최종적으로 결과값을 반환한다.

커링 사용 예시 2)

function log(logMessage = console.log, date, importance, text) {
  logMessage(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${text}`);
}

const curriedLog = curry(log);
// curriedLogByConsole 은 log의 첫 번째 인수가 고정된 partial 이 된다.
const curriedLogByConsole = curriedLog(console.log); 
// logNow 는 log의 첫 번째 인수, 두 번째 인수가 고정된 partial 이 된다.
const logNow = curriedLogByConsole(new Date());
// infoNow 는 log의 첫 번째 인수, 두 번째 인수, 세 번째 인수가 고정된 partial 이 된다.
const infoNow = logNow("INFO");

logNow("ERROR", "에러 발생"); // [HH:mm] ERROR 에러 발생
infoNow("메세지"); // [HH:mm] INFO 메세지

출처

https://ko.javascript.info/currying-partials 

https://my-first-programming.tistory.com/entry/%EC%BB%A4%EB%A7%81-Currying-%EC%9D%B4%EB%9E%80 

복사했습니다!