您的位置:首页 > Web前端 > JavaScript

函数式编程初探(Javascript)

2014-02-15 17:15 501 查看
最近学习函数式编程,对于其中“没有副作用的函数”感觉最为深刻,这样的函数测试起来不受外界环境影响,实在是以后写程序的一个指导方向

使用Javascript进行实验主要还是编写和调试方便,本文代码都在Chrome下面运行成功。

Javascript不支持尾递归优化,这一点在编写的过程中实验数据变大的时候会出现调用堆栈溢出的问题,目前常见的语言对尾递归优化要么是没有要么是不完全,根据网上资料gcc可以通过编译参数进行尾递归优化,python也有支持尾递归的版本。

下面进行一个简单的例子来看看程序是怎么演化的:

目标:生成小于等于Max的素数列表

function getPrimeList(max) => [2,3,5,7,...]

首先生成一个[2..max]的列表,在erlang之类的语言里面生成这样的列表非常容易,在javascript里面就要自己生成了

function range(min, max) //=> [min..max];
{
var arr = [];
for(var i = min; i < max+1; i++) arr[i - min] = i;
return arr;
}


在函数式变成里面不提倡使用for/while等循环操作,这里我们尝试改为递归的方式
function range(min, max) //=> [min..max];
{
return min == max ? [min] : [min].concat(range(min+1, max));
}


分析这个函数中递归的range不是最后一个指令,不符合尾递归的条件,运行时会造成大量的调用堆栈对用,我们尝试修改成尾递归版本,一般情况下尾递归的做法就是把中间结果当成参数
function rangeAndList(min, max, list) //=> [min..max];
{
return min == max ? list.concat(min) : rangeAndList(min+1, max, list.concat(min));
}
function range(min, max){return rangeAndList(min, max, [])}


我们完成了尾递归版本的range函数,然后就看生成素数列表的方法了

判断一个数p是否为素数,我们假设已经获得了所有小于p的素数的列表list和p的开平方数sqrtp
function isPrime(p, list, sqrtp)
{
return list.every(function(prime){return prime > sqrtp || p%prime})
}


现在我们可以通过reduce方法生成所有的素数了
function getPrimeList(max)
{
return range(2, max).reduce(function(list,p){return isPrime(p,list,Math.sqrt(p)) ? list.concat(p) : list}, [])
}


完整代码:
function rangeAndList(min, max, list) //=> [min..max];
{
return min == max ? list.concat(min) : rangeAndList(min+1, max, list.concat(min));
}
function range(min, max){return rangeAndList(min, max, [])}
function isPrime(p, list, sqrtp) { return list.every(function(prime){return prime > sqrtp || p%prime}) }
function getPrimeList(max) { return range(2, max).reduce(function(list,p){return isPrime(p,list,Math.sqrt(p)) ? list.concat(p) : list}, []) }
//Test
console.log(getPrimeList(100));


如果不使用Array的reduce方法

function isPrime(p, list, sqrtp)
{
return list.every(function(prime){return prime > sqrtp || p%prime})
}
function getPrimeWithList(max, min, list)
{
return max == min ? list :
getPrimeWithList(max, min + 1, isPrime(min,list,Math.sqrt(min)) ? list.concat(min) : list);
}
function getPrimeList(max)
{
return getPrimeWithList(max, 2, []);
}


在上面的代码中,主要使用了函数式编程中的几个基本功能:

高阶函数,函数作为参数,函数没有副作用不依赖外部环境,不修改状态尾递归列表的reduce,every

由于Javascript没有对尾递归进行优化,代码很容易运行堆栈溢出,另外对数组的concat操作频繁也比较消耗资源

初学,请大家指正。

参考:http://www.ruanyifeng.com/blog/2012/04/functional_programming.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息