乐趣区

函数柯里化

什么是“函数柯里化”
curry 的概念: 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数
先看一个简单例子,add 函数接受 2 个参数(或者多个),addX 函数接受 1 个参数。换而言之,所谓 ” 柯里化 ”,就是把一个多参数的函数,转化为单参数函数。将一个函数转换为一个新的函数
// 非柯里化
function add(x, y) {
return x + y;
}

add(1, 2) === 3; // true

// 柯里化
function addX(y) {
return function(x) {
return x + y;
};
}

addX(2)(1) == 3; // true
柯里化的好处
我能想到的是:

代码复用,减少维护成本
尽可能的函数化,便于阅读

“ 函数式编程 ” 是一种 ” 编程范式 ”(programming paradigm),也就是如何编写程序的方法论。
所以,不用想太多,就是一种规范一样的东西~ ~
如何实现柯里化函数 curry
先来看一个栗子(这里借助了 ramda,请自行安装 ),在下面的栗子中我们对 add 进行了柯里化,从结果上可以看到当参数为 1 个时返回的是个函数,当参数为 2 个的时候返回函数,当参数为 3 个的时候返回函数执行结果。
var _ = require(“ramda”);

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

var curry_add = _.curry(add);

console.log(curry_add(1)); // 输出函数
console.log(curry_add(1)(2)); // 输出函数
console.log(curry_add(1)(2)(3)); // 输出结果
根据上述的小栗子,可以得到,柯里化后的函数如果接受到全部参数则返回函数执行结果,否则返回一个柯里化函数。
很容易想到以下伪代码
var curry = function(fn) {
return function() {
// 假设柯里化的函数叫 curry_fn
// if “curry_fn 接受到的参数数量等于 fn 接受参数的数量 ”
// return “fn 的执行结果 ”
// else return “ 一个柯里化函数 ”
};
};
上述伪代码是不是很像递归?

递归出口:curry_fn 接受到的参数数量等于 fn 接受参数的数量
重复逻辑:return “ 一个柯里化函数 ”

于是有了以下简单实现柯里化的代码
var curry = function(fn) {
var limit = fn.length; // fn 接受的参数个数
var params = []; // 存储递归过程的所有参数,用于递归出口计算值

return function _curry(…args) {
params = params.concat(args); // 收集递归参数
if (limit <= params.length) {
// 返回函数执行结果
return fn.apply(null, params);
} else {
// 返回一个柯里化函数
return _curry;
}
};
};
参考资料

JS 函数式编程指南
函数式编程入门教程
一行写出 javascript 函数式编程中的 curry

退出移动版