前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >进大厂之必会的函数柯里化(Currying)

进大厂之必会的函数柯里化(Currying)

作者头像
公众号---人生代码
发布2021-03-16 14:32:53
5420
发布2021-03-16 14:32:53
举报
文章被收录于专栏:人生代码

深入了解函数柯里化

curry是一种处理函数的高级技术。它不仅在JavaScript中使用,也在其他语言中使用。

套用是函数的一种转换,将函数从可调用的f(a, b, c)转换为可调用的f(a)(b)(c)

curry不调用函数。它只是改变了它。

让我们先看一个例子,以便更好地理解我们正在讨论的内容,然后看实际应用程序。

我们将创建一个辅助函数curry(f),它执行对两个参数fcurry。换句话说,对于两个参数f(a, b)curry(f)将其转换为一个以f(a)(b)的方式运行的函数:

代码语言:javascript
复制
function curry(f) { // curry(f) does the currying transform
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}

// usage
function sum(a, b) {
  return a + b;
}

let curriedSum = curry(sum);

alert( curriedSum(1)(2) ); // 3

如您所见,实现很简单:它只是两个包装器。

curry(func)的结果是一个包装函数(a)

当像curriedSum(1)那样调用时,参数被保存在词法环境中,并返回一个新的包装器函数(b)

然后用2作为参数调用这个包装器,并将调用传递给原始的sum

更高级的套用实现,例如lodash库中,返回一个允许函数被正常或部分调用的包装器:

代码语言:javascript
复制
function sum(a, b) {
  return a + b;
}

let curriedSum = _.curry(sum); // using _.curry from lodash library

alert( curriedSum(1, 2) ); // 3, still callable normally
alert( curriedSum(1)(2) ); // 3, called partially

为了理解这些好处,我们需要一个有价值的现实例子。

例如,我们有日志功能log(date、importance、message)来格式化和输出信息。在实际的项目中,这样的函数有很多有用的特性,比如通过网络发送日志,这里我们只使用alert:

代码语言:javascript
复制
function log(date, importance, message) {
  alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}

对其进行函数柯里化

代码语言:javascript
复制
log = _.curry(log);

日志正常工作后:

代码语言:javascript
复制
log(new Date(), "DEBUG", "some debug"); // log(a, b, c)

也可以使用 柯里化

代码语言:javascript
复制
log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)

现在我们可以很容易地为当前日志创建一个方便的函数:

代码语言:javascript
复制
// logNow will be the partial of log with fixed first argument
let logNow = log(new Date());

// use it
logNow("INFO", "message"); // [HH:mm] INFO message

现在logNow是带有固定第一个参数的日志,换句话说就是“部分应用函数”或简称为“partial”。

我们可以更进一步,为当前调试日志创建一个方便的函数:

代码语言:javascript
复制
let debugNow = logNow("DEBUG");

debugNow("message"); // [HH:mm] DEBUG message

所以:

curry后我们没有丢失任何东西:log仍然可以正常调用。

我们可以很容易地生成部分函数,比如今天的日志。

进阶的柯里化实现

如果您想了解更多细节,这里是我们可以在上面使用的多参数函数的“高级”curry实现。

很短:

代码语言:javascript
复制
function curry(func) {

  return function curried(...args) {
    if (args.length >= func.length) {
      return func.apply(this, args);
    } else {
      return function(...args2) {
        return curried.apply(this, args.concat(args2));
      }
    }
  };

}

案例

代码语言:javascript
复制
function sum(a, b, c) {
  return a + b + c;
}

let curriedSum = curry(sum);

alert( curriedSum(1, 2, 3) ); // 6, still callable normally
alert( curriedSum(1)(2,3) ); // 6, currying of 1st arg
alert( curriedSum(1)(2)(3) ); // 6, full currying

新的curry看起来可能很复杂,但实际上很容易理解。

curry(func)调用的结果是这样的包装器curry:

代码语言:javascript
复制
// func is the function to transform
function curried(...args) {
  if (args.length >= func.length) { // (1)
    return func.apply(this, args);
  } else {
    return function(...args2) { // (2)
      return curried.apply(this, args.concat(args2));
    }
  }
};

当我们运行它时,有两个if执行分支:

如果传入的args count与原始函数的定义(function.length)相同或更多,则只需使用function.apply将调用传递给它。

否则,得到一个部分:我们还没有调用func。相反,将返回另一个包装器,它将重新应用curry,同时提供以前的参数和新的参数。

然后,如果我们再次调用它,我们将得到一个新的部分(如果没有足够的参数),或者最终得到结果。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CryptoCode 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 深入了解函数柯里化
  • 进阶的柯里化实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档