zoukankan      html  css  js  c++  java
  • Javascript函数式编程的一些例子[转载]

    函数式编程风格

    通常来讲,函数式编程的谓词(关系运算符,如大于,小于,等于的判断等),以及运算(如加减乘数等)都会以函数的形式出现,比如:
        a > b
    通常表示为:
        gt(a, b)//great than
    因此,可以首先对这些常见的操作进行一些包装,以便于我们的代码更具有“函数式”风格:
    function abs(x){ return x>0?x:-x;}
    function add(a, b){ return a+b; }
    function sub(a, b){ return a-b; }
    function mul(a, b){ return a*b; }
    function div(a, b){ return a/b; }
    function rem(a, b){ return a%b; }
    function inc(x){ return x + 1; }
    function dec(x){ return x - 1; }
    function equal(a, b){ return a==b; }
    function great(a, b){ return a>b; }
    function less(a, b){ return a<b; }
    function negative(x){ return x<0; }
    function positive(x){ return x>0; }
    function sin(x){ return Math.sin(x); }
    function cos(x){ return Math.cos(x); }

    如果我们之前的编码风格是这样:
    // n*(n-1)*(n-2)*...*3*2*1
    function factorial(n){
        if(n == 1){
            return 1;
        }else{
            return n * factorial(n - 1);
        }
    }

    在函数式风格下,就应该是这样了:
    function factorial(n){
        if(equal(n, 1)){
            return 1;
        }else{
            return mul(n, factorial(dec(n)));
        }
    }

    函数式编程的特点当然不在于编码风格的转变,而是由更深层次的意义。比如,下面是另外一个版本的阶乘实现:
    /*
    * product <- counter * product
    * counter <- counter + 1
    * */
    function factorial(n){
        function fact_iter(product, counter, max){
            if(great(counter, max)){
                return product;
            }else{
                fact_iter(mul(counter, product), inc(counter), max);
            }
        }
        return fact_iter(1, 1, n);
    }

    虽然代码中已经没有诸如+/-/*//之类的操作符,也没有>,<,==,之类的谓词,但是,这个函数仍然算不上具有函数式编程风格,我们可以改进一下:
    function factorial(n){
        return (function factiter(product, counter, max){
            if(great(counter, max)){
                return product;
            }else{
                return factiter(mul(counter, product), inc(counter), max);
            }
        })(1, 1, n);
    }
    factorial(10);

    通过一个立即运行的函数 factiter,将外部的 n 传递进去,并立即参与计算,最终返回运算结果。

    Y-结合子

    提到递归,函数式语言中还有一个很有意思的主题,即:如果一个函数是匿名函数,能不能进行递归操作呢?如何可以,怎么做?我们还是来看阶乘的例子:
    function factorial(x){
        return x == 0 ? 1 : x * factorial(x-1);
    }

    factorial 函数中,如果 x 值为 0,则返回 1,否则递归调用 factorial,参数为 x 减 1,最后当 x 等于 0 时进行规约,最终得到函数值(事实上,命令式程序语言中的递归的概念最早即来源于函数式编程中)。现在考虑:将 factorial 定义为一个匿名函数,那么在函数内部,在代码 x*factorial(x-1)的地方,这个 factorial 用什么来替代呢?

    lambda 演算的先驱们,天才的发明了一个神奇的函数,成为 Y-结合子。使用 Y-结合子,可以做到对匿名函数使用递归。关于 Y-结合子的发现及推导过程的讨论已经超出了本部分的范围,有兴趣的读者可以参考附录中的资料。我们来看看这个神奇的 Y-结合子:
    var Y = function(f) {
        return (function(g) {
            return g(g);
        })(function(h) {
            return function() {
                return f(h(h)).apply(null, arguments);
            };
        });
    };

    我们来看看如何运用 Y-结合子,依旧是阶乘这个例子:
    var factorial = Y(function(func){
        return function(x){
            return x == 0 ? 1 : x * func(x-1);
        }
    });
    factorial(10);

    或者:
    Y(function(func){
        return function(x){
            return x == 0 ? 1 : x * func(x-1);
        }
    })(10);

    不要被上边提到的 Y-结合子的表达式吓到,事实上,在 JavaScript 中,我们有一种简单的方法来实现 Y-结合子:
    var fact = function(x){
        return x == 0 : 1 : x * arguments.callee(x-1);
    }
    fact(10);

    或者:
    (function(x){
        return x == 0 ? 1 : x * arguments.callee(x-1);
    })(10);//3628800

    其中,arguments.callee 表示函数的调用者,因此省去了很多复杂的步骤。

    其他实例

    下面的代码则颇有些“开发智力”之功效:
    //函数的不动点
    function fixedPoint(fx, first){
        var tolerance = 0.00001;
        function closeEnough(x, y){return less( abs( sub(x, y) ), tolerance)};
        function Try(guess){//try 是javascript中的关键字,因此这个函数名为大写
            var next = fx(guess);
            //print(next+" "+guess);
            if(closeEnough(guess, next)){
                return next;
            }else{
                return Try(next);
            }
        };
        return Try(first);
    }
    // 数层嵌套函数,
    function sqrt(x){
        return fixedPoint(
            function(y){
                return function(a, b){ return div(add(a, b),2);}(y, div(x, y));
            },
        1.0);
    }
    print(sqrt(100));

    fiexedPoint 求函数的不动点,而 sqrt 计算数值的平方根。这些例子来源于《计算机程序的构造和解释》,其中列举了大量的计算实例,不过该书使用的是 scheme 语言,在本书中,例子均被翻译为 JavaScript。

  • 相关阅读:
    Django 之Redis配置
    python之类中如何判断是函数还是方法
    Anaconda 虚拟环境安装及应用
    【转载】IDEA:XML配置提示URI is not registered
    idea中配置xml不自动提示解决方案
    Java接口成员变量和方法默认修饰符
    [转载]java中Date,SimpleDateFormat
    intellij idea 的全局搜索快捷键方法
    【转载】使用IntelliJ IDEA提示找不到struts-default文件
    【转载】Jmeter分布式部署测试-----远程连接多台电脑做压力性能测试
  • 原文地址:https://www.cnblogs.com/zfc2201/p/3159984.html
Copyright © 2011-2022 走看看