函数式编程小结(一)
首先是在用underscore的map,reduce的时候接触到函数式编程。这种新的编程范式,感觉还是挺有意思的。
特点
1.在函数式编程中函数和变量是等价的,函数可以作为参数,可以作为返回值,也可以赋值给其他变量。
var hello=function(){
return function(){
return 'hello';
}
}
2.除了函数的重要性以外,函数式编程的一个重要的特点就是不变性,不对变量做更改,每一次操作都返回一个新的值。
//对于((a+1)*2)^2
//命令式编程
a=1;
a=a+1;
a=a*2;
a=a*a;
function add(a,b){
return a+b;
}
function mul(a,b){
return a*b;
}
function sqr(a){
return a*a;
}
sqr(mul(add(1,1),2));
3.函数式编程推荐的是不对变量做修改,所以函数式编程没有迭代,所以用递归来完成。
迭代是对一个状态的不断改变,直到状态不改变为止,实际上迭代就是步骤式的将完成任务的步骤描述一遍。
递归的过程是在是描述这个任务本身。从代码上来看,递归是更加易读的。
//fabonacci
//iteration
function fabonacci_iter(n){
var a=1,b=1,res=0;
for(var i=0;i<n-1;i++){
res=a+b,a=b,b=res;
}
return res;
}
//过程中修改res的值,直到结束,这就是个迭代的过程。
//recursion
function fabonacci_recur(n){
if(n==0||n==1)return 1;
return fabonacci_recur(n-1)+fabonacci_recur(n-2);
}
//这就是递归的过程,过程中不会对变量做更改,每次操作返回一个新的值。
//而且递归的过程是在描述这个任务本身,fabonacci就是将自己的前两个数相加,这个递归代码就很清晰的描述了这件事。
当然,从这个代码来看递归相对来说效率较低,因为他没有保存之前计算的值,当然对于函数式编程,也是有办法可以保存的。不过也可以将代码写成尾递归的形式,编译器在保存return时就不需要保存变量信息。
//尾递归形式,但是其实感觉这个形式就没有递归那么直观了。
function fabonacci_recur_tail(n,a,b){
if(n==0||n==1)return b;
return fabonacci_recur_tail(n-1,b,a+b);
}
可以利用闭包,对做过的操作做记忆,也可以提高效率。以下代码参考Javascript权威指南。
function memo(f){
var cache={};
return function(){
var key=Array.prototype.join.call(arguments,',');
if(key in cache)return cache[key];
return cache[key]=f.apply(this,arguments);
}
}
var fabonacci=memo(fabonacci_recur);
fabonacci(5);
//这个memo保存了1到4的结果。
优点
1.引用透明
因为函数式编程不会对传入的参数做更改,所以在调用函数,传入引用也不需要担心会修改原来的值。同时也天然适合于并发编程,不需要加锁,这个听起来还是非常的诱人的。
2.符合自然的思维
函数式编程是在描述任务是在干什么,而不是在讲述要怎么做(虽然对于习惯了命令式编程的人来说并没有什么用)。
3.代码热部署(这一点需要研究研究)
4.适合数学推导
对于函数式编程,输入某个状态的参数,就能够返回确定状态的值,不会受其他影响,函数符合数学的推导方式,例如可以证明函数是否等价。