currying

4120 단어

what's currying

var add = function(a,b){
  return a + b
}
add(2,3)  //5

curry화는add(2,3)를add(2)(3)로 바꾸는 것이다
var add = function(a){
  return function(b){
    return a + b;
  }
}
add(2)(3)    //5

여기서 무슨 일이 일어났는지 자세히 봅시다
var add2 = add(2)
console.log(add2)  //[Function]
add2(3)  //5
add2(5)  //7

우리는add(2)가 되돌아오는 함수를 알아차렸습니다. 이 함수는 매개 변수를 받아들여 두 개를 더한 후에 되돌아옵니다.currying은 일종의 미리 불러오는 기술과 같다.많은 경우에 우리가 함수를 호출하려면 여러 개의 매개 변수가 필요하지만, 어느 단계에서는 그 중의 일부분의 매개 변수만 알고 있다. 괜찮다. 먼저 알고 있는 매개 변수를 전송하고 새로운 함수를 되돌려준다. 모든 매개 변수가 받아들여질 때 진정한 호출 함수를 사용한다.

why currying


currying의 장점은 매우 많은데, 뚜렷한 점은 우리가currying으로 더욱 우호적인 함수를 쓸 수 있다는 것이다.함수가 호출되는 모든 파라미터를 모를 때가 많습니다. 이때currying은 매우 유용합니다!다음은 상자를 축소하고 색칠을 할 수 있는 함수를 쓰겠습니다.
var scale = function(val, stuff){
  stuff.size *= val
}
var paint = function(val, stuff){
  stuff.color = val
}

var ScaleAndPaint = function(s, color, stuff){
  scale(s, stuff)
  paint(color, stuff)
}

저희가 이 함수를 테스트해 보도록 하겠습니다.
var box = {
  size: 10,
  color: 'green'
}

ScaleAndPaint(2,'black',box)
console.log(box)    //{ size: 20, color: 'black' }

works great! 그러나 이때 우리는 거의 모든 상자가 두 배만 되면 된다는 것을 발견했다. 그러나 우리는 매번 2로 전해져야 한다는 것은 정말 불친절하다.다음은 저희의 함수를 currying화합니다.
var ScaleAndPaint = function(s){
  return function(color){
    return function(stuff){
      scale(s, stuff)
      paint(color, stuff)
    }
  }
}

두 배로 커지잖아, 간단해.
var DoubleAndPaint = ScaleAndPaint(2)

한 걸음 더 나아가다
var DoubleAndBlue = DoubleAndPaint('blue')
var DoubleAndRed = DoubleAndPaint('Red')
DoubleAndBlue(box)   //{ size: 40, color: 'blue' }

lodash


currying화된 함수는 정말 사용하기 편하지만, 우리는 그것이 원래의 그 함수보다 훨씬 번거로워서 여러 번 끼워 넣는 반환 함수가 필요하다는 것을 알아차렸다.또 다른 문제는currying을 배우기 전에 우리는 이미 우리의 함수를 썼는데, 지금 우리는 그것을curry화하고 싶은데, 어떻게 합니까?
다행히도 우리는 많은 프레임워크가 일반 함수인currying화된api를 실현했다. 예를 들어lodash와ramda를 사용하면 너무 간단하지 않다.
var curry = require('lodash').curry;
var ScaleAndPaint = curry(function(s, color, stuff){
  scale(s, stuff)
  paint(color, stuff)
})
ScaleAndPaint(2)('black')(box)

works great!

스스로 실현!

var slice = Array.prototype.slice;
var toArray = function(a){ return slice.call(a) }
// , arguments , concat 
var concatArgs = function(args1, args2){
    return args1.concat(toArray(args2));
}
// , 
var trimArrLength = function(arr, length){
    if ( arr.length > length ) return arr.slice(0, length);
    else return arr;
}

// , 6
var createFn = function(fn, args, totalArity){
  var remainingArity = totalArity - args.length;
  switch(remainingArity){
    case 0: return function(){ return processInvocation(fn, concatArgs(args, arguments), totalArity) };
        case 1: return function(a){ return processInvocation(fn, concatArgs(args, arguments), totalArity) };
        case 2: return function(a,b){ return processInvocation(fn, concatArgs(args, arguments), totalArity) };
        case 3: return function(a,b,c){ return processInvocation(fn, concatArgs(args, arguments), totalArity) };
        case 4: return function(a,b,c,d){ return processInvocation(fn, concatArgs(args, arguments), totalArity) };
        case 5: return function(a,b,c,d,e){ return processInvocation(fn, concatArgs(args, arguments), totalArity) };
        case 6: return function(a,b,c,d,e,f){ return processInvocation(fn, concatArgs(args, arguments), totalArity) };
  }
}

var processInvocation = function(fn, argsArr, totalArity){
    argsArr = trimArrLength(argsArr, totalArity);
    if ( argsArr.length === totalArity ) return fn.apply(null, argsArr);
    return createFn(fn, argsArr, totalArity);
}

var curry = function(fn){
  return createFn(fn, [], fn.length)
}

테스트 해봐.
var add = curry(function(a,b,c,d,e){return a+b+c+d+e})
console.log(add(1,2)(3,4)(5))   //15

works great!

I love currying!!!

좋은 웹페이지 즐겨찾기