函数式编程初探(Javascript)

最近学习函数式编程,对于其中“没有副作用的函数”感觉最为深刻,这样的函数测试起来不受外界环境影响,实在是以后写程序的一个指导方向
使用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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值