zoukankan      html  css  js  c++  java
  • 函数的柯里化

    currying

    首先我们讨论的是函数柯里化(function currying)。currying 的概念最早由俄国数学家 Moses
    Schönfinkel 发明,而后由著名的数理逻辑学家 Haskell Curry 将其丰富和发展,currying 由此得名。

    currying 又称部分求值。一个 currying 的函数首先会接受一些参数,接受了这些参数之后,
    该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保
    存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。

    从字面上理解 currying 并不太容易,我们来看下面的例子。

    假设我们要编写一个计算每月开销的函数。在每天结束之前,我们都要记录今天花掉了多少
    钱。代码如下:

    var monthlyCost = 0; 
     
    var cost = function( money ){ 
        monthlyCost += money; 
    }; 
     
    cost( 100 );    // 第 1 天开销 
    cost( 200 );    // 第 2 天开销 
    cost( 300 );    // 第 3 天开销 
    //cost( 700 );    // 第 30 天开销 
     
    alert ( monthlyCost );      // 输出:600 

    通过这段代码可以看到,每天结束后我们都会记录并计算到今天为止花掉的钱。但我们其实
    并不太关心每天花掉了多少钱,而只想知道到月底的时候会花掉多少钱。也就是说,实际上只需
    要在月底计算一次。

    如果在每个月的前 29 天,我们都只是保存好当天的开销,直到第 30 天才进行求值计算,这
    样就达到了我们的要求。虽然下面的 cost 函数还不是一个 currying 函数的完整实现,但有助于
    我们了解其思想:

    var cost = (function(){ 
        var args = []; 
     
        return function(){ 
            if ( arguments.length === 0 ){     
                var money = 0; 
                for ( var i = 0, l = args.length; i < l; i++ ){     
                    money += args[ i ]; 
                } 
                return money; 
            }else{ 
                [].push.apply( args, arguments ); 
            } 
        } 
     
    })(); 


    cost( 100 ); // 未真正求值
    cost( 200 ); // 未真正求值
    cost( 300 ); // 未真正求值

    console.log( cost() ); // 求值并输出:600

     

    接下来我们编写一个通用的 function currying(){},function currying(){}接受一个参数,即
    将要被 currying 的函数。在这个例子里,这个函数的作用遍历本月每天的开销并求出它们的总和。
    代码如下:

    var currying = function( fn ){ 
        var args = []; 
     
        return function(){ 
            if ( arguments.length === 0 ){ 
                return fn.apply( this, args ); 
            }else{ 
                [].push.apply( args, arguments ); 
                return arguments.callee; 
            }  
        } 
     
    };
    
    var cost = (function(){ 
        var money = 0; 
        return function(){ 
            [...arguments].forEach(function(item) {
              money += item; 
            })  
            return money; 
        } 
     
    })(); 
    
    var cost = currying( cost );    // 转化成 currying 函数 
    
    cost( 100 );    // 未真正求值 
    cost( 200 );    // 未真正求值   
    cost( 300 );    // 未真正求值 
     
    alert ( cost() );     // 求值并输出:600 

    至此,我们完成了一个 currying 函数的编写。当调用 cost()时,如果明确地带上了一些参数,
    表示此时并不进行真正的求值计算,而是把这些参数保存起来,此时让 cost 函数返回另外一个
    函数。只有当我们以不带参数的形式执行 cost()时,才利用前面保存的所有参数,真正开始进行
    求值计算。

  • 相关阅读:
    Sencha touch 初体验
    Android开发——NDK开发入门
    Android开发——Activity(活动)的生命周期(上)
    Android开发——构建自定义组件【转】
    Android开发——使用Gallery实现“多级联动”
    Android开发——Android搜索框架(一)
    LINQ之路 6:延迟执行(Deferred Execution)
    .Net小笔记之.NET Framework的内容
    c#高级编程学习笔记之创建一个简化的链表类
    C#高级编程读书笔记之泛型的优点
  • 原文地址:https://www.cnblogs.com/mafeifan/p/5970147.html
Copyright © 2011-2022 走看看