커링

커링

커링은 f(a, b, c) 처럼 단일 호출로 처리하는 함수를 f(a)(b)(c) 와 같이 각각의 인수가 호출 가능한 프로세스로 호출된 후 병합되도록 변환하는 것이다.

사용예시 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function curry(f) {
return function (a) {
return function (b) {
return f(a, b);
};
};
}

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

let curriedSum = curry(sum);

alert(curriedSum(1)(2)); // 3

lodash 라이브러리의 _.curry 같이 래퍼를 반환할 대 함수가 보통 때처럼 또는 partial 적으로 호출하는 것을 허용하는 더 진복적으로 구현된 커링도 있다.

1
2
3
4
5
6
7
8
function sum(a, b) {
return a + b;
}

let carriedSum = _.curry(sum); // lodash 라이브러리의 _.carry 사용

alert(carriedSum(1, 2)); // 3, 보통 때처럼
alert(carriedSum(1)(2)); // 3, partially 호출되었음

커링은 어디에 써야할까요?

예시: 로그함수

1
2
3
function log(date, importance, message) {
alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}

커링을 적용

1
log = _.curry(log);

둘다 정상 작동

1
2
log(new Date(), "DEBUG", "some debug");
log(new Date())("DEBUG")("some debug");

아래처럼 현재 시간으로 로그를 출력하는데 편리하도록 log 함수를 사용할 수 있다.

1
2
3
4
// logNow 는 log 첫 번째 인수가 고정된 partial이 될것이다.
let logNow = log(new Date());

logNow("INFO", "mesage");

디버깅 로그를 편리하게 하는 함수를 만들 수 도 있다.

1
2
3
let debugNow = logNow("DEBUG");

debugNow("message");

고급 커리 구현

다중 인수를 호용하는 고급 커리를 구현하는 방법.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args);
} else {
return function (...args2) {
return curried.apply(this, args.concat(args2));
};
}
};
}

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

let curriedSum = curry(sum);

alert(curriedSum(1, 2, 3));
alert(curriedSum(1)(2, 3));
alert(curriedSum(1)(2)(3));

sum.length = 3 이다. 만약 curriedSum(1)(2)(3)을 호출하면 다음과 같이 실행된다.

  1. curriedSum(1) 이 실행될때 인수의 개수가 3보다 작으므로 else를 타서 실행된다.
  2. curriedSum(1)(2) 가 실핼될때 arg.concat을 통해 인수를 모아주었으므로 curriedSum(1, 2) 와 같고 이것도 인수의 갯수가 3보다 작으니 else를 타고 curried가 반환된다.
  3. curriedSum(1)(2)(3) 이 호출되면 인수를 다 모으고 curriedSum(1, 2, 3) 이 호출되는 것과 같다.

커리은 고정된 길이의 함수들만 사용 가능하다. f(...args) 같이 나머지 매개변수를 사용하는 함수는 이러한 방법으로 커리할 수 없다.