게시글

강좌34 - JavaScript - 4년 전 등록 / 3년 전 수정

Currying(커링) vs Partial application

안녕하세요. 이번 시간에는 함수형 프로그래밍 기법 중 하나인 커링partial application에 대해 알아보겠습니다.

Partial application

쉽게 설명하자면, 여러 개의 인자를 받는 함수가 있을 때 일부의 인자를 고정한 함수를 만드는 기법입니다. 코드로 보면 이해하기 쉽습니다.

var plus = function(a, b, c) {
  return a + b + c;
};

위와 같은 평범한 함수에서, partial application을 구현하기 위해 함수의 prototype에 특별한 메소드를 추가합니다. 그래야 모든 함수에서 partial application을 사용할 수 있으니까요.

Function.prototype.partial = function() {
  var args = [].slice.apply(arguments);
  var self = this;
  return function() {
    return self.apply(null, args.concat([].slice.apply(arguments)));
  };
};

코드를 보죠. args는 arguments를 복사한 겁니다. 그리고 함수를 return 하는데 args는 클로저의 변수로 저장됩니다. 그리고 이제 새로운 함수에 인자가 들어왔을 때 기존에 있던 args와 concat하는거죠.

var plusa = plus.partial(1);
plusa(2, 3); // 6
var plusb = plusa.partial(2);
plusb(4); // 7
var plusab = plus.partial(1, 3);
plusab(5); // 9

이렇게 일부 인자만 받은 새로운 함수를 만들고, 나중에 새로운 함수에 인자를 넣어 완성합니다.

bind 함수를 쓰면 더 깔끔합니다. 위의 partial 메소드를 prototype에 추가할 필요 없이

var plusa = plus.bind(null, 1);
plusa(2, 3); // 6
var plusb = plusa.bind(null, 2);
plusb(4); // 7
var plusab = plus.bind(null, 1, 3);
plusab(5); // 9

하면 됩니다! 그냥 bind를 씁시다. 

Currying

currying도 partial application처럼 인자를 미리 고정할 수 있지만 하나씩만 고정한다는 것이 특징입니다. 또한, 모든 인자를 받을 때까지 계속 함수를 생성합니다. 매 번 인자를 1개씩 고정하는 연속적인 partial application으로 볼 수도 있습니다.

function multiplyThree(x) {
  return function(y) {
    return function(z) {
      return x * y * z;
     }
  };
}
multiplyThree(4)(8)(2); // 64

위의 함수는 일종의 커링입니다. 인자를 하나씩 세 번 받아야 호출됩니다.

그런데 인자가 100개라면, 저렇게 일일이 함수를 만들 수는 없겠죠? curry를 구현해봅시다.

Function.prototype.curry = function(one) {
  var origFunc = this;
  var target = origFunc.length;
  var args = [];
  function next(nextOne) {
    args = args.concat(nextOne);
    if (args.length === target) {
      return origFunc.apply(null, args);
    } else {
      return function(nextOne) { return next(nextOne) };
    }
  }
  return next(one);
}

이제 인자를 네 개를 받는 multiplyFour 함수에 커링을 적용해봅시다.

function multiplyFour(w, x, y, z) {
  return w * x * y * z;
}
multiplyFour.curry(2)(3)(4)(5); // 120

커링이 적용되었습니다.

차이점

둘의 차이점을 간단히 정리해보겠습니다. partial application은 기존 함수의 매개변수들 중 일부를 미리 넣어둔 새로운 함수를 만드는 것입니다. 만들어진 partial application 함수는 다음 번 호출 시에는 결과를 반환해야 합니다.

반면에 currying은 기존 함수의 매개변수를 하나씩 받는 방법입니다. 매개변수를 모두 받을 때까지 새로운 함수를 반환하고요.

인자가 두 개일 때는 커링이나 파샬 어플리케이션이나 별 차이가 없습니다. (한 개일 때는... ㅎㅎ). 그리고 인자가 세 개 이상인 경우는 Partial application이나 커링 중에 선택하면 됩니다.

다음 시간에는 재귀메모이제이션에 대해 알아보겠습니다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.

댓글

2개의 댓글이 있습니다.
일 년 전
partial application에서 var args = arguments해도 될 것 같은데 var args = [].slice.apply(arguments); 를 왜 하는지 궁금합니다.
5달 전
arguments는 유사 배열이라서 concat을 이용 불가능 하기 때문에 [].slice.apply(arguments)를 사용한 것 입니다.
2년 전
늘 잘보고 갑니다.