Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

我理解的函数柯里化 #14

Open
zhaoqize opened this issue Jan 24, 2018 · 2 comments
Open

我理解的函数柯里化 #14

zhaoqize opened this issue Jan 24, 2018 · 2 comments
Labels

Comments

@zhaoqize
Copy link
Owner

zhaoqize commented Jan 24, 2018

对于函数柯里化之前就了解过,大概知道是个什么东西。
最近在读Vue源码的时候,看到了 cached 函数的使用,让我觉得这个代码写的挺有意思,于是在sf发问,看了 @sunyongjian 回答,于是又绕到了 柯里化高阶函数上

柯里化定义

维基中有对柯里化的定义:在计算机科学中,柯里化(英语:Currying),又译为卡瑞化加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

用JavaScript表达定义

着重看 多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数

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

使用

foo(1) // f (b) {  return function(c) { return a+b+c } }
foo(1)(2) // f (c) {  return a+b+c }
foo(1)(2)(3)  // 6

其实就是逐渐消元的过程。知乎上也有类似的问题,具体见:如何理解functional programming里的currying与partial application

通用的柯里化函数

上面的例子虽然解释了什么是柯里化,但是还不通用,因为 参数个数 理论上是无法估计的。

下面就是一个抽象的柯里化函数

var currying = function(fn) {
  var args = [...arguments].slice(1);

  return function() {
    if (arguments.length === 0) {
      return fn.apply(this, args); // 没传参数时,调用这个函数
    } else {
      [].push.apply(args, arguments); // 传入了参数,把参数保存下来
      return arguments.callee; // 返回这个函数的引用
    }
  }
}

场景使用

实际场景的运用能更好的加深我们的理解,所以我们用实际的生活场景来看看 柯里化 如何运用。

场景:记账本,每天记录使用多少钱,一个月算一次总花费(或者在我想要知道的时候)

function account(){
   var total = [];
   function money(p) {
     if (arguments.length === 0) {
       // 计算一共花了多少钱
       total = total.reduce((sum, value) => {
          return sum + value;
       }, 0)
       console.log('一共花了', total+' 元');
     } else {
       // 记录每天花了多少钱
       total.push(p)
       console.log('今天花了', p+' 元');
     }
   }
   return money;
}

这个我们就定义好了一个 柯里化 的记账本。
我们来用一下

var spend = account();
spend(15) // 今天花了 15 元
spend(30) // 今天花了 30 元
spend() // 一共花了 45 元 (不传参数的时候就返回真正的结果)

Tip:高阶函数:一个函数接收另一个函数作为其参数。

何时使用柯里化

参考:函数式编程与面向对象编程[1]: Lambda表达式 函数柯里化 高阶函数

如果某些参数在大部分情况下,总是需要同时给出,才具有真实的意义,那么应该把这些参数组合成一个组合型参数来处理,而不应该科里化。
如果要定义的多参函数是一个闭合函数,那么它是很可能需要被多次应用的,这种情况下,应该用组合型参数的方式来处理。
如果先指定某一些参数就有明确的意义,那么就应该用科里化的方式来处理。

@wind13
Copy link

wind13 commented May 24, 2018

Cool and easy!

1 similar comment
@wind13
Copy link

wind13 commented May 24, 2018

Cool and easy!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants