大家不要被这个名字诱惑,我讲的是javascript的高阶函数的概念,而不是说本教程为高阶教程。

最近研究SICP,对其中的高阶函数抽象有了一些体会,并用javascript中进行了一些实验,现在把这些实验分析一下,希望对大家有所帮助。

高阶函数思想由来已久,最早可能要追溯到可计算理论的初期,在lambda演算理论中就有了这个思想了。最早的实现可能算是lisp语言。可以说,这个运算模型跟图灵机的计算能力是相当的。只不过后来历史选择了冯诺依曼体系。而lambda只好作为一个虚拟的实现运行在具有同等计算能力的图灵机上。

更高层次的抽象

抽象具有层次,比如,将一个小的运算封装成一个函数,就是一层抽象,而在这个抽象的基础上,再进行一次抽象,即为高阶抽象。在lisp之类的函数编程语言中这个概念是比较基本的。而在其他的命令式编程语言,如C,java等中,提供的是模板或者接口这样的概念。

比如,我们每次需要计算一个数的立方数时,都需要写成x*x*x的形式,如果一个运算中有很多地方要用到立方这种运算的话,可能编码会非常麻烦,而且代码也不清晰,于是,我们可以将立方运算抽象成一个函数,这个函数接受一个输入,并返回这个输入的立方数。
比如:

Js代码
  1. function cube(x){return x*x*x;}
Js代码
  1. function cube(x){return x*x*x;}
function cube(x){return x*x*x;}

这样,我们就有了一个独立的模块,用以计算“立方”,并且通过扩展语言的原生语句,我们可以表达“立方”这个概念。这种抽象是容易理解的,像C,java等语言也提供此类的抽象。

下面再看一个例子:

我们先编写一个函数,这个函数的功能如下:

  1. 输入一个范围[a,b]
  2. 输出为这个范围中的数的和。

如输入[1,100],输出5050.

这个函数通过递归的形式比较容易实现,如:

Js代码
  1. function intSum(a, b){
  2. function inc(x){ return x + 1; }
  3. function identity(x){ return x; }
  4. if(a > b){
  5. return 0;
  6. }else{
  7. return intSum( inc(a) , b) + identity(a);
  8. }
  9. }
Js代码
  1. function intSum(a, b){
  2. function inc(x){ return x + 1; }
  3. function identity(x){ return x; }
  4. if(a > b){
  5. return 0;
  6. }else{
  7. return intSum( inc(a) , b) + identity(a);
  8. }
  9. }
function intSum(a, b){
function inc(x){ return x + 1; }
function identity(x){ return x; }
if(a > b){
return 0;
}else{
return intSum( inc(a) , b) + identity(a);
}
}

当然,其中的内部函数inc,identity实在太简单,完全可以忽略,但是考虑到后边要用到,就先写成这种形式。

这个函数可以很好的工作,但是,随着项目的增大,我们需要另外一个函数来计算某个范围内数的立方和。

  1. 输入一个范围[a,b]
  2. 输出为这个范围中的数的立方和

如输入[1,4],输出100:1^3+2^3+3^3+4^3 = 1 + 8 + 27 + 64 = 100

这时候,我们同样可以用一个递归来实现这个函数:

Js代码
  1. function cubeSum(a, b){
  2. function inc(x){ return x + 1; }
  3. function cube(x){ return x * x * x; }
  4. if(a > b){
  5. return 0;
  6. }else{
  7. return cubeSum( inc(a) , b) + cube(a);
  8. }
  9. }
Js代码
  1. function cubeSum(a, b){
  2. function inc(x){ return x + 1; }
  3. function cube(x){ return x * x * x; }
  4. if(a > b){
  5. return 0;
  6. }else{
  7. return cubeSum( inc(a) , b) + cube(a);
  8. }
  9. }
function cubeSum(a, b){
function inc(x){ return x + 1; }
function cube(x){ return x * x * x; }
if(a > b){
return 0;
}else{
return cubeSum( inc(a) , b) + cube(a);
}
}

随着项目的进一步增长,我们现在需要实现第三个函数,来对这样一个数列进行求和输入同样为[a,b]的一个范围,计算1/x*(x+2),且步长为4,这个数列的前n项的和有个性质,就是无限的接近pi/8这个数列当然是有用的,比如计算Pi值,我们给定一个比较大的范围如[1,10000]然后给这个值乘8,即可近似的计算出pi来。


我用mathematica 计算了一下,可以看出这个求和确实是极限于PI/8.

同样用递归可以实现这个函数:

Js代码
  1. function piSum(a, b){
  2. function piTerm(x){ return 1/((x+2)*x); }
  3. function piNext(x){ return x+4; }
  4. if(a > b){
  5. return 0;
  6. }else{
  7. return piSum( piNext(a) , b) + piTerm(a);
  8. }
  9. }
Js代码
  1. function piSum(a, b){
  2. function piTerm(x){ return 1/((x+2)*x); }
  3. function piNext(x){ return x+4; }
  4. if(a > b){
  5. return 0;
  6. }else{
  7. return piSum( piNext(a) , b) + piTerm(a);
  8. }
  9. }
function piSum(a, b){
function piTerm(x){ return 1/((x+2)*x); }
function piNext(x){ return x+4; }
if(a > b){
return 0;
}else{
return piSum( piNext(a) , b) + piTerm(a);
}
}

现在,让我们比较一下这三个函数,很快我们就会发现,这三个函数太相似了,都是:

  1. 比较范围的下标,如果a>b,返回0,否则,转2
  2. 改变a的值,并对a作一定的运算,然后递归调用自身

可以写成下面的这种伪码形式:

Java代码
  1. function <funcName>(a, b){
  2. if(a > b){
  3. return 0;
  4. }else{
  5. return <funcName>(<next>(a), b) + <func>(a);
  6. }
  7. }
Java代码
  1. function <funcName>(a, b){
  2. if(a > b){
  3. return 0;
  4. }else{
  5. return <funcName>(<next>(a), b) + <func>(a);
  6. }
  7. }
function <funcName>(a, b){
if(a > b){
return 0;
}else{
return <funcName>(<next>(a), b) + <func>(a);
}
}

其中,funcName为函数名,next为取下一个a的值(根据“步长”走一步),func计算a。

我们很容易将这个代码翻译成javascript代码:

Js代码
  1. function sum(term, a, next, b){
  2. if(a > b){
  3. return 0;
  4. }else{
  5. return sum(term, next(a), next, b) + term(a);
  6. }
  7. }
Js代码
  1. function sum(term, a, next, b){
  2. if(a > b){
  3. return 0;
  4. }else{
  5. return sum(term, next(a), next, b) + term(a);
  6. }
  7. }
function sum(term, a, next, b){
if(a > b){
return 0;
}else{
return sum(term, next(a), next, b) + term(a);
}
}

这时候,如果我们传递给sum这个函数两个额外的参数term,和next,我们就可以得到想要的结果.
现在,我们的求和函数就可以写成这种形式:

Js代码
  1. function intSum(a, b){
  2. function inc(x){return x + 1;}
  3. function identity(x){return x;}
  4. return sum(identity, a, inc, b);
  5. }
Js代码
  1. function intSum(a, b){
  2. function inc(x){return x + 1;}
  3. function identity(x){return x;}
  4. return sum(identity, a, inc, b);
  5. }
function intSum(a, b){
function inc(x){return x + 1;}
function identity(x){return x;}
return sum(identity, a, inc, b);
}

同样,立方和的函数可以写成这样:

Js代码
  1. function cubeSum(a, b){
  2. function inc(x){return x + 1;}
  3. function cube(x){return x * x * x;}
  4. return sum(cube, a, inc, b);
  5. }
Js代码
  1. function cubeSum(a, b){
  2. function inc(x){return x + 1;}
  3. function cube(x){return x * x * x;}
  4. return sum(cube, a, inc, b);
  5. }
function cubeSum(a, b){
function inc(x){return x + 1;}
function cube(x){return x * x * x;}
return sum(cube, a, inc, b);
}

最后一个

Js代码
  1. function piSum(a, b){
  2. function piTerm(x){ return 1/((x+2)*x); }
  3. function piNext(x){ return x+4; }
  4. return sum(piTerm, a, piNext, b);
  5. }
Js代码
  1. function piSum(a, b){
  2. function piTerm(x){ return 1/((x+2)*x); }
  3. function piNext(x){ return x+4; }
  4. return sum(piTerm, a, piNext, b);
  5. }
function piSum(a, b){
function piTerm(x){ return 1/((x+2)*x); }
function piNext(x){ return x+4; }
return sum(piTerm, a, piNext, b);
}

可以看到,我们只需要传递给sum一个真正的计算算子和一个计算步长的算子就可以了。

现在给出一个简单的测试函数:

Js代码
  1. function sumTester(){
  2. print(intSum(1, 100));      //  should print 5050
  3. print(cubeSum(1, 4));       //  should print 100
  4. print(piSum(1, 10000)*8);   //  should print PI
  5. }
Js代码
  1. function sumTester(){
  2. print(intSum(1, 100));      //  should print 5050
  3. print(cubeSum(1, 4));       //  should print 100
  4. print(piSum(1, 10000)*8);   //  should print PI
  5. }
function sumTester(){
print(intSum(1, 100));      //  should print 5050
print(cubeSum(1, 4));       //  should print 100
print(piSum(1, 10000)*8);   //  should print PI
} 

两者的运行结果都如下:

写道
js> sumTester()
5050
100
3.141392653591793

顺便说一下,这些例子均在rhino下测试,在浏览器中没有做过测试,如最后的测试函数中的print,估计浏览器中嵌入的js引擎不能正确解析。关于rhino,javaeye里有相关的文章,可以找找看。

使用高阶函数,我们可以在第一阶抽象的基础上再做一次抽象,生成一个函数的产生器,传递给一定的算子,即可完成各个相似的计算。

转载:

http://mysougou.javaeye.com/blog/636299

js 立方 平方怎么写相关推荐

  1. C#程序设计--任何一个自然数m的立方均可写成m个连续奇数之和

    题目:任何一个自然数m的立方均可写成m个连续奇数之和 例如: 1^3=1; 2^3=3+5: 3^3=7+9+11; 4^3=13+15+17+19 5^3=21+23+25+27+29 编程实现:输 ...

  2. 自然数分解:任何一个自然数m的立方均可写成m个连续奇数之和。编程实现:输入一自然数 n,求组成 n3的 n个连续奇数。

    标题 自然数分解 类别 流程控制 时间限制 2S 内存限制 1000Kb 问题描述 任何一个自然数m的立方均可写成m个连续奇数之和.例如: 13=1 23=3+5 33=7+9+11 43=13+15 ...

  3. 2.任何一个自然数m的立方均可写成m个连续奇数之和

    任何一个自然数m的立方均可写成m个连续奇数之和.例如: 1^3=1 2^3=3+5 3^3=7+9+11 4^3=13+15+17+19 输入一自然数n,求组成n3的n个连续奇数. n= int(in ...

  4. JS 面试问题: 手写 new

    JS 面试问题: 手写 new

  5. 【递推】任何一个自然数的立方都可以写成一串连续奇数之和问题 C

    描述 任何一个自然数的立方都可以写成一串连续奇数之和. 如: 13=1 23=3+5=8 33=7+9+11=27 43=13+15+17+19=64 ---------. 要求 编程输入N,求N3是 ...

  6. 验证尼科彻斯定理,即:任何一个整数m的立方都可以写成m个连续奇数之和。 例如: 1^3=1 2^3=3+5 3^3=7+9+11 4^3=13+15+17+19

    题目描述: 验证尼科彻斯定理,即:任何一个整数m的立方都可以写成m个连续奇数之和. 例如: 1^3=1 2^3=3+5 3^3=7+9+11 4^3=13+15+17+19 输入描述: 输入一个int ...

  7. 验证尼科彻斯定理,即:任何一个整数m的立方都可以写成m个连续奇数之和。

    一.尼科彻斯定理是什么? 尼科彻斯定理可以叙述为:任何一个整数的立方都可以表示成一串连续的奇数的和. 例如: 1^3=1 2^3=3+5 3^3=7+9+11 4^3=13+15+17+19 这其实就 ...

  8. 如何在浏览器上跑深度学习模型?并且一行JS代码都不用写

    翻译 | 林椿眄 编辑 | 周翔 2017 年 8 月,华盛顿大学的陈天奇团队发布了 TVM,和 NNVM 一起组成深度学习到各种硬件的完整优化工具链,支持手机.CUDA.OpenCL.Metal.J ...

  9. 网站真分页js代码该怎么写?

    真分页这个词对程序猿们来说,并不是一个陌生的词汇,但是如果你是初次学习真分页,或许还是得花点时间小小研究下,下面是之前去转盘网(喜欢的可以看看,也可以进入引擎模式)的真分页js部分代码,html部分的 ...

最新文章

  1. ComplexHeatmap绘制热图(一)
  2. Javascript实现网页水印(非图片水印)
  3. JSTL中fmt标签详解
  4. PERFORMANCE-MONITORING(转)
  5. Korney Korneevich and XOR(CF750F1/F2)
  6. interface关键字
  7. Bash脚本教程之命令提示符
  8. define定义的函数如何引用_「C与指针心得」25.预处理器-宏函数
  9. 保姆级计算机视觉学习路线
  10. 数据科学 IPython 笔记本 8.2 Matplotlib 的应用
  11. LINUX 循环fork()
  12. go语言通道插入0_使用Go语言常遇到的问题
  13. Android6.0指纹识别开发
  14. 【生产调度】基于matlab遗传算法求解柔性生产调度(FJSP)问题【含Matlab源码 1780期】
  15. c语言程序设计基础课本答案,c语言程序设计基础课后习题参考 答 案与解析.doc...
  16. hibernate之c3p0连接池配置详解
  17. 2019年安徽省学业水平考试计算机,2019年安徽省初中学业水平考试
  18. ios 拍照上传到服务器_iOS 上传图片到服务器
  19. net core 微服务 快速开发框架 Viper 初体验
  20. hexo嵌入html传消息的,Hexo添加Toc支持,生成文章目录

热门文章

  1. python numpy安装教程_python3.6下Numpy库下载与安装图文教程
  2. 2021年全球药用蘑菇提取物收入大约415.3百万美元,预计2028年达到649.7百万美元
  3. (五证合一)法人和其他组织统一社会信用代码编码规则
  4. 听心 文/一个会写诗的程序员
  5. 红米note4x开启root权限
  6. js给动态创建出来的元素添加事件
  7. Virtual Box安装Ubuntu
  8. 100例经典Python核心实战提升练习题汇总(三)
  9. git拉取远程新分支到本地
  10. HTTP协议1)----对于应用层的详细讲解