부분 적용과 커링은 다항 함수의 인자를 줄이는 기법입니다. 우선 다항 함수나 커링을 이용해 인자의 개수를 줄이는 것이 왜 중요한지에 대해 알아보기 위해 메서드 체인과 함수 파이프라인에 대해 알아보겠습니다.
메서드 체인과 함수 파이프라인
메서드 체인과 함수 파이프라인은 함수들을 연쇄적으로 실행하는 방법입니다. 함수의 출력값을 다음 함수의 입력값으로 사용하는 것입니다.
메서드 체이닝은 다음과 같은 형태로 되어있습니다.
const array = [1,2,3,4,6,7,8]
const isEven = num => num % 2 === 0
const square = num => num * num
const add = (num1, num2) => num1 + num2
const result = array
.filter(isEven)
.map(square)
.reduce(add, 0)
이처럼 자료구조의 메서드들을 연결하여 원하는 결과를 얻는 것입니다. 이를 통해 선언적으로 코드를 작성해 구조적으로 향상되고 가독성이 좋아집니다. 다만 단점도 있습니다. 바로 각 메서드가 해당 자료구조에 선언되어 있어야 한다는 것입니다. 이렇게 되면 자료구조와 함수(메서드)들간의 단단한 결합이 생기고 표현성이 제한됩니다. 이번에는 함수 파이프라인에 대해 알아보겠습니다.
const array = [1,2,3,4,5,6,7,8]
const isEven = num => num % 2 === 0
const square = num => num * num
const add = (num1, num2) => num1 + num2
// map, filter, reduce 함수들은 선언되었다고 가정
const result = reduce(map(filter(array, isEven)), square), add, 0)
코드상으로는 가독성이 안좋지만 이는 추후 pipe 함수로 수정할 수 있습니다. 그보다는 메서드 체인과는 다르게 객체에 의존하지 않기 때문에 함수 입출력을 서로 연결지어 느슨하게 결합된 것이 중요합니다. array라는 변수가 실제 배열이 아니어도 동일한 인터페이스를 가진다면 이 함수를 사용할 수 있습니다.
메서드 체인과 함수 파이프라인은 함수를 연결하는 방식들입니다. 함수를 연결하기 위해서는 중요한 점이 있는데, 바로 함수가 취하는 인수 개수가 이 전 함수의 리턴값의 개수와 같아야 한다는 것입니다. 사실 함수는 여러개의 인자를 갖을 수 있지만, 리턴 값의 개수는 오직 하나입니다. 따라서 인자의 개수(항수)가 여러개인 경우 함수 파이프라인이나 메서드 체인에 사용하기 복잡해집니다. 이를 해결하기 위해, 우리는 커링이나 부분 적용을 통해 인자의 개수를 하나로 만들어 사용할 수 있습니다.
커링
커링과 부분 적용이 왜 필요한지에 대해 알아봤으니 이제 커링에 대해서 자세하게 알아보겠습니다. 커링은 다항함수를 단항함수로 변경해주는 기법입니다. 우선 일반 평가와 커리된 평가의 차이점에 대해서 알아보겠습니다. 자바스크립트에서는 일반 함수를 호출할 때 인수가 모자라도 문제 없이 호출됩니다. f(a,b,c)인 함수에 인자 a값만 넣어서 호출하면 자동으로 b, c의 값을 undefined로 설정하여 함수를 호출합니다.
function f(a,b,c) {
return a + b + c
}
f(10) // b, c는 undefined로 설정되어 함수가 호출됨
커리된 평가의 경우, 일부 인수만 넣어서 함수를 호출하면, 나머지 함수를 기다리는 새로운 함수가 반환됩니다. 예를 들어 f(a)를 호출하면 새로운 함수 f(b,c)를 반환합니다. 그리고 모든 인수가 채워지면 그제서야 실제로 함수가 호출됩니다.
즉, 커링은 다변수 함수가 인수를 전부 받을때까지 실행을 지연하여 단계별로 단항 함수의 순차열로 전환하는 기법입니다. 커링함수를 구현해보겠습니다.
function curry2 (fn) {
return function(arg1) {
return function(arg2) {
return fn(arg1, arg2)
}
}
}
// 화살표 함수를 이용하면 더 간단하게 작성가능합니다.
const curry2 = fn => arg1 => arg2 => fn(arg1, arg2)
curry2는 두개 인자를 받는 함수를 단항함수를 순차적으로 반환하는 함수로 변환하는 함수입니다. 인수가 개수에 상관없이 커링할때는 라이브러리의 도움을 받으면 됩니다.
커링 기법을 사용한다면 다항 함수를 단항함수로 바꿔, 파이프라인에 연결해도 잘 작동할 수 있도록 합니다.
부분 적용
그렇다면 부분 적용은 무엇일까요? 부분 적용은 함수의 인자중 일부(부분)를 고정(적용)하여 새로운 함수를 반환하는 기법입니다. 코드로 보겠습니다.
function partial(fn, …params1) {
return function(…params2) {
return fn.apply(null, params1.concat(params2))
}
}
이처럼 params1에서 필요한 인자중 일부를 미리 받고, 추후에 인자들을 추가적으로 받아서 둘을 합쳐서 함수를 호출하는 기법입니다.
자바스크립트에서는 bind를 이용해 쉽게 부분 적용을 구현할 수 있습니다.
function add(x, y) {
return x + y;
}
const add5 = add.bind(null, 5);
add5(3) // 8
커링과 부분 적용의 차이
커링은 다항함수를 연속적인 여러개의 단항 함수로 바꾸는 기법입니다. 부분 적용은 다항 함수의 인자 일부를 고정하는 기법입니다. 둘의 목적은 모두 다항 함수의 인수를 줄이는 데에 있습니다. 그러나 커링의 경우 항상 단항 함수를 반환하지만, 부분 적용은 그렇지 않습니다.
마무리
이번엔 커링과 부분 적용 기법에 대해 알아봤습니다. 이 두 기법은 함수 합성을 위해 중요한 역할을 합니다. 다음 글에서는 함수 조합기들에 대해서 알아보겠습니다.
정리
- 함수 파이프라인을 위해서 다항 함수를 단항 함수로 변경해야 한다.
- 이를 위해 부분 적용, 커링 기법을 이용할 수 있다.
- 커링은 다항 함수를 연속된 단항 함수들로 변경하는 기법이다.
- 부분 적용은 다항 함수의 일부 인수를 고정하는 기법이다.
- 자바스크립트에서 부분 적용은 bind 메서드를 사용해 쉽게 구현할 수 있다.
'함수형 프로그래밍' 카테고리의 다른 글
| 함수형 자바스크립트 (6-1) - 함수자, 모나드를 이용한 예외처리 (0) | 2022.10.09 |
|---|---|
| 함수형 자바스크립트 (5) - 함수 조합기 (0) | 2022.09.08 |
| 함수형 자바스크립트 (2) - 자바스크립트와 함수형 프로그래밍 (0) | 2022.08.26 |
| 함수형 자바스크립트 (1) - 함수형으로 사고하기 (0) | 2022.08.23 |