Currying은 1967년 Christopher Strachey가 수학자이며 논리학자인 하스켈 커리(Haskell Brooks Curry)의 이름을 따서 명명.
-
여러개의 인자를 가진 함수를 호출 할 경우, 파라미터의 수보다 적은 수의 파라미터를 인자로 받으면 누락된 파라미터를 인자로 받는 기법.
-
여러 인자를 입력받는 함수를 인자 하나만 입력 받는 함수들의 시퀀스로 변환하는 것.
- 인자 하나를 입력 받고 값 대신 함수를 반환
- 반환된 함수는 다음 인자를 입력으로 받음.
- 위의 과정을 모든 입력 값을 처리하고 반환하는 값이 하나만 남을 때까지 반복.
코드
1
2
3
| // 일반 function
const add2 = (x, y) => x + y;
add(1, 2) // 3
|
1
2
3
4
5
6
7
| const addCurring = x => y => x + y;
// y => x + y 에서 x는 클로저 사용
addCurring(1); // y => x + y
addCurring(1)(2); // 3
const addOne = addCurring(1);
addOne(2) // 3
|
사용예
1
2
3
| const addCurring = x => y => x + y;
const addOne = addCurring(1);
addOne(2) // 3
|
1
2
3
4
| const addCurring = x => y => z => x + y + z;
const addOne = addCurring(1);
const addTwo = addOne(1);
addTwo(1) // 3
|
사용처
함수를 재사용하는데 매우 좋다
아래는 로그를 찍는 함수이다.
1
2
3
4
5
6
| const LogLevel = { debug: 'debug', error: 'error'}
const logMessage = (logLevel, message) => console.log(`${logLevel} ${message}`)
logMessage(LogLevel.debug, 'log 1st');
logMessage(LogLevel.debug, 'log 2nd');
logMessage(LogLevel.debug, 'log 3rd');
|
커링을 이용하여 debug와 error로 사용가능 하다.
1
2
3
4
5
6
7
8
9
10
| const LogLevel = { debug: 'debug', error: 'error'}
const logger = level => message => console.log(`${level} ${message}`)
const debug = logger(LogLevel.debug)
const error = logger(LogLevel.error)
debug('log 1st')
debug('log 2st')
error('log 1st')
error('log 2st')
|
반복하여 출력하는 다른 예
1
2
3
4
5
6
7
8
9
10
11
| let LogLevel = { debug: 'debug', error: 'error'}
let fruits: [String] = ["Apple", "Banana", "Peach", "Grape"]
let logger = (level, message) => console.log(`${level} ${message}`)
fruits.forEach(fruit => {
logMessage(LogLevel.debug, fruit);
}
fruits.forEach {fruit => {
logMessage(LogLevel.error, fruit)
}
|
커링을 사용한 경우
1
2
3
4
5
6
7
8
| let LogLevel = { debug: 'debug', error: 'error'}
let fruits = ["Apple", "Banana", "Peach", "Grape"]
let logger = level => message => console.log(`${level} ${message}`)
let debug = logger(LogLevel.debug)
let error = logger(LogLevel.error)
fruits.forEach(debug);
fruits.forEach(error);
|
함수를 입력 받아 currying 함수로 변환하는 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| var curryIt = function(uncurried) {
var parameters = Array.prototype.slice.call(arguments, 1);
return function() {
return uncurried.apply(this, parameters.concat(
Array.prototype.slice.call(arguments, 0)
));
};
};
var greeter = function(greeting, separator, emphasis, name) {
console.log(greeting + separator + name + emphasis);
};
var greetHello = curryIt(greeter, "Hello", ", ", ".");
greetHello("Heidi"); //"Hello, Heidi."
greetHello("Eddie"); //"Hello, Eddie."
|
Note
- Ramda와 같은 함수형 자바스크립트 라이브러리는 필요한 매개변수를 구분할 수 있는 보다 유연한 커링 함수들이 있다.
- Currying을 넓게 쓰고 싶으면 라이브러리를 사용하는 것이 좋다.
- Currying 함수에 일관된 네이밍 규칙을 적용하면 코드 가독성이 좋아진다.
- 함수에서 파생된 다른 함수들은 작동방식이 명확해야 하며 어떤 인자가 들어오는지 알 수 있어야 한다.
인자 순서의 중요성
- 인자의 순서는 매우 중요. 앞쪽의 인자일수록 변동 가능성이 적고, 뒤의 인자 일수록 변동 가능성이 높다.