函数式编程风格

通常来讲,函数式编程的谓词(关系运算符,如大于,小于,等于的判断等),以及运算(如加减乘数等)都会以函数的形式出现,比如:
    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。

Javascript函数式编程的一些例子[转载]的更多相关文章

  1. 一文带你了解JavaScript函数式编程

    摘要: 函数式编程入门. 作者:浪里行舟 Fundebug经授权转载,版权归原作者所有. 前言 函数式编程在前端已经成为了一个非常热门的话题.在最近几年里,我们看到非常多的应用程序代码库里大量使用着函 ...

  2. 转:JavaScript函数式编程(三)

    转:JavaScript函数式编程(三) 作者: Stark伟 这是完结篇了. 在第二篇文章里,我们介绍了 Maybe.Either.IO 等几种常见的 Functor,或许很多看完第二篇文章的人都会 ...

  3. 转: JavaScript函数式编程(二)

    转: JavaScript函数式编程(二) 作者: Stark伟 上一篇文章里我们提到了纯函数的概念,所谓的纯函数就是,对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环 ...

  4. 转:JavaScript函数式编程(一)

    转:JavaScript函数式编程(一) 一.引言 说到函数式编程,大家可能第一印象都是学院派的那些晦涩难懂的代码,充满了一大堆抽象的不知所云的符号,似乎只有大学里的计算机教授才会使用这些东西.在曾经 ...

  5. javascript函数式编程和链式优化

    1.函数式编程理解 函数式编程可以理解为,以函数作为主要载体的编程方式,用函数去拆解.抽象一般的表达式 与命令式相比,这样做的好处在哪?主要有以下几点: (1)语义更加清晰 (2)可复用性更高 (3) ...

  6. JavaScript 函数式编程读书笔记2

    概述 这是我读<javascript函数式编程>的读书笔记,供以后开发时参考,相信对其他人也有用. 说明:虽然本书是基于underscore.js库写的,但是其中的理念和思考方式都讲的很好 ...

  7. JavaScript 函数式编程读书笔记1

    概述 这是我读<javascript函数式编程>的读书笔记,供以后开发时参考,相信对其他人也有用. 说明:虽然本书是基于underscore.js库写的,但是其中的理念和思考方式都讲的很好 ...

  8. JavaScript函数式编程(纯函数、柯里化以及组合函数)

    JavaScript函数式编程(纯函数.柯里化以及组合函数) 前言 函数式编程(Functional Programming),又称为泛函编程,是一种编程范式.早在很久以前就提出了函数式编程这个概念了 ...

  9. 学会JavaScript函数式编程(第1部分)

    摘要: JS函数式编程入门. 原文:学会使用函数式编程的程序员(第1部分) 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 在这篇由多部分组成的文章中,接下来将介绍函数式编程的一些概念 ...

随机推荐

  1. layui文件单文件和多文件的上传、预览以及删除和修改

    活不多说,直接上代码 单文件上传 1.HTML <blockquote class="layui-elem-quote layui-quote-nm" style=" ...

  2. 怎么WordPress增加在线投稿功能

    现在很多个人博客为了增加博客的内容,都会提供投稿通道,大部分都是以邮箱的形式进行投稿,不过这样一来,也很费人力,要拷贝复制,然后编辑等.如果给博客加个在线投稿功能,那就方便多了.稍微审核下文章内容就可 ...

  3. kubernetes如何要使用用户名和密码登陆harbor以拉取docker镜像,应该如何操作?

    还好,网上有相应的CASE处理. http://www.jianshu.com/p/ffbfb44dc496 =========================== 先生成名为为regsecret的S ...

  4. AC日记——小A的糖果 洛谷七月月赛

    小A的糖果 思路: for循环贪心: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #defi ...

  5. Java 类、属性、方法修饰符 public、private、protected、default

    Java 中修饰类修饰符:public .default (默认) Java 中修饰类中属性.方法修饰符:public.private.protected.default (默认) 通过 IDEA 创 ...

  6. 自动选择profile

    cobbler system list cobbler profile list 方式一:自动选择profile cobbler system add --name="linux-node1 ...

  7. Eclipse IDE下的Spring框架使用简单实例

    Eclipse IDE下的Spring框架使用简单实例 1 准备Java jdk安装. Eclipse软件安装.根据系统安装32/64版本,选择Eclipse IDE for Java Develop ...

  8. 解决Mysql 服务无法启动 服务没有报告任何错误

    MySQL数据库在升级到5.7版本后,和之前的版本有些不一样,没有data文件夹,我们都知道MySQL数据库文件是保存在data文件夹中的,网上有人说把5.6版本的data文件夹拷贝一个,这种说法听听 ...

  9. thinkphp join 表前缀

    public function get_user_group_title($uid){ $pre = C('DB_PREFIX'); $res = M('AuthGroupAccess aga')-& ...

  10. js中__proto__和prototype的区别和关系

          首先,要明确几个点:1.在JS里,万物皆对象.方法(Function)是对象,方法的原型(Function.prototype)是对象.因此,它们都会具有对象共有的特点.即:对象具有属性_ ...