有时候你可能会写出这样的函数:
function foo(n, flag){
var ret = 1;
if(flag) for(var i = 1; i <= n; i++) ret *= i;
ret += n;
if(flag) ret /= n;
return ret;
}
也许情况比这个更复杂,总之你希望用一个参数来控制程序流,这相当于你有一个配置函数的需求。
为什么不试试柯里化呢:
function foo(flag){
return function(n){
var ret = 1;
if(flag) for(var i = 1; i <= n; i++) ret *= i;
ret += n;
if(flag) ret /= n;
return ret;
};
}
foo(true)(5); // 25
foo(false)(5); // 6
这个时候你就可以简单地取一个函数别名了:
var foo1 = foo(true);
var foo2 = foo(false);
foo1(5); // 25
foo2(5); // 6
这样就做到了函数的配置。
相比另外一种方案:
function foo(n, flag){
var ret = 1;
if(flag) for(var i = 1; i <= n; i++) ret *= i;
ret += n;
if(flag) ret /= n;
return ret;
}
function foo1(n) {
return foo(true, n);
}
function foo2(n) {
return foo(false, n);
}
最终效果是相同的,但后者没有将函数作为参数的做法是不符合函数式编程范式的。
上一篇博文中描述的One Line DFT也有柯里化的写法:
// recursive DFT
recursiveDFT = (inverse) => (a) => a.length == 1 ? a : flatten(transpose(transpose(a.reduce((pre, cur, i) => pre[i & 1].push(cur) && pre, [[], []]).map(v => recursiveDFT()(v))).map((v, i) => [complex.add(v[0], complex.mul(complex.fromAngle(i * (inverse ? -2 * Math.PI / a.length : 2 * Math.PI / a.length)), v[1])), complex.minus(v[0], complex.mul(complex.fromAngle(i * (inverse ? -2 * Math.PI / a.length : 2 * Math.PI / a.length)), v[1]))]))).map(v => inverse ? complex.numMul(1 / a.length, v) : v);
DFT = recursiveDFT(false);
inverseDFT = recursiveDFT(true);
var arr = [complex(3), complex(4), complex(0), complex(0)]
var rarr = DFT(arr);
inverseDFT(rarr); // almost equals to arr
这样就封装了两个子函数,看起来比较优雅。