函数式编程初探(Javascript)
2014-02-15 17:15
501 查看
最近学习函数式编程,对于其中“没有副作用的函数”感觉最为深刻,这样的函数测试起来不受外界环境影响,实在是以后写程序的一个指导方向
使用Javascript进行实验主要还是编写和调试方便,本文代码都在Chrome下面运行成功。
Javascript不支持尾递归优化,这一点在编写的过程中实验数据变大的时候会出现调用堆栈溢出的问题,目前常见的语言对尾递归优化要么是没有要么是不完全,根据网上资料gcc可以通过编译参数进行尾递归优化,python也有支持尾递归的版本。
下面进行一个简单的例子来看看程序是怎么演化的:
目标:生成小于等于Max的素数列表
function getPrimeList(max) => [2,3,5,7,...]
首先生成一个[2..max]的列表,在erlang之类的语言里面生成这样的列表非常容易,在javascript里面就要自己生成了
在函数式变成里面不提倡使用for/while等循环操作,这里我们尝试改为递归的方式
分析这个函数中递归的range不是最后一个指令,不符合尾递归的条件,运行时会造成大量的调用堆栈对用,我们尝试修改成尾递归版本,一般情况下尾递归的做法就是把中间结果当成参数
我们完成了尾递归版本的range函数,然后就看生成素数列表的方法了
判断一个数p是否为素数,我们假设已经获得了所有小于p的素数的列表list和p的开平方数sqrtp
现在我们可以通过reduce方法生成所有的素数了
完整代码:
如果不使用Array的reduce方法
在上面的代码中,主要使用了函数式编程中的几个基本功能:
高阶函数,函数作为参数,函数没有副作用不依赖外部环境,不修改状态尾递归列表的reduce,every
由于Javascript没有对尾递归进行优化,代码很容易运行堆栈溢出,另外对数组的concat操作频繁也比较消耗资源
初学,请大家指正。
参考:http://www.ruanyifeng.com/blog/2012/04/functional_programming.html
使用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
相关文章推荐
- JavaScript面向对象初探——原型链、封装和继承
- 函数式编程初探
- javascript 函数式编程(4)
- ArcGIS API for JavaScript开发初探——基础知识
- javascript中的事件代理初探
- javascript 事件代理初探
- 函数式编程初探
- 函数式编程初探
- 函数式编程FP前言Javascript,有人称其为C+LISP,C只怕是尽人皆知
- 初探JavaScript魅力(2)
- javascript 函数初探 (六)--- 闭包初探#1
- javascript很好很强大-->(1)javascript面象对象初探
- JavaScript学习五 函数式编程中的一些关于函数的术语
- 初探Google Chrome对下个版本JavaScript的支持
- JavaScript初探知识总结
- JavaScript初探之匿名函数
- 初探 JavaScript 中的函数式编程
- 翻译连载 |《你不知道的JS》姊妹篇 |《JavaScript 轻量级函数式编程》- 第 1 章:为什么使用函数式编程?
- JavaScript初探之——图片移动
- 函数式编程初探