Thinking in scala (5)----高阶函数*
高阶函数是函数式编程里面一个非常重要的特色,所谓的高阶函数,就是以其它函数作为参数的函数。
下面以一个小例子演示Scala的高阶函数特性,非常有意思,也非常强大。
首先看这么一个程序:
code1:
object higherorderfuntion{
def sum1(a:Int,b:Int):Int=
if(a>b) 0
else a+sum1(a+1,b)
def sum2(a:Int,b:Int):Int=
if(a>b) 0
else cube(a)+sum2(a+1,b)
def sum3(a:Int,b:Int):Int=
if(a>b) 0
else fac(a)+sum3(a+1,b)
def cube(a:Int):Int=a*a*a
def fac(a:Int):Int=
if (a==0) 1
else a*fac(a-1)
def main(args:Array[String])={
println(sum1(1,3))
println(sum2(1,3))
println(sum3(1,3))
}
}
上面这个例子“没有”用到高阶函数,sum1是计算a+(a+1)+(a+2)+...+(b), sum2是计算a^3+(a+1)^3+(a+2)^3+...+b^3,
sum3是计算a!+(a+1)!+(a+2)!+...+b!。分析sum1,sum2,sum3的代码,很容易发现这三个函数有着相似的“Pattern”,
抛开函数名不论,这三个函数唯一的区别在于,在 else语句中对a的处理:a, cube(a) , fac(a). 那么来看,在函数式
编程里面,是如何非常精彩的利用这个“Pattern”来使得代码更加精简的:
code2:
object higherorderfuntion{
def sum(f:Int=>Int,a:Int,b:Int):Int=
if(a>b) 0
else f(a)+sum(f,a+1,b)
def sumInt(a:Int,b:Int):Int = sum(id,a,b)
def sumCube(a:Int,b:Int):Int = sum(cube,a,b)
def sumFac(a:Int,b:Int):Int = sum(fac,a,b)
def id(a:Int) = a
def cube(a:Int):Int=a*a*a
def fac(a:Int):Int=
if (a==0) 1
else a*fac(a-1)
def main(args:Array[String])={
println(sumInt(1,3))
println(sumCube(1,3))
println(sumFac(1,3))
}
}
重头戏来了,我们来看sum函数的实现:
def sum(f:Int=>Int,a:Int,b:Int):Int=
if(a>b) 0
else f(a)+sum(f,a+1,b)
sum函数接收三个参数,第二个和第三个参数分别是: a:Int 和 b:Int, 这和第一个例子中是一样的。
比较令人费解的是sum函数的第一个参数:f:Int=>Int
这个是什么意思呢?意思是sum函数接收一个名字叫做 “f” 的函数作为参数,而 Int=>Int 是对f的说明:
=>左边的Int是说:函数f接收一个Int类型的参数,
=>右边的Int是说:函数f的返回值是Int类型的。
好了,那么既然sum函数接收函数f作为一个参数,那么sum就可以利用f了,事实也是这样的,看sum
函数的else语句就知道了:f(a)
然后再看sumInt、sumCube和sumFac三个函数的定义:
def sumInt(a:Int,b:Int):Int = sum(id,a,b) def sumCube(a:Int,b:Int):Int = sum(cube,a,b) def sumFac(a:Int,b:Int):Int = sum(fac,a,b)
以sumCube函数为例吧,它在定义的时候,把cube函数作为参数,传递给sum函数,
而我们看cube函数的定义:
def cube(a:Int):Int=a*a*a
发现,cube函数接收一个Int作为参数,并且返回一个Int,也就是说cube函数是符合sum函数的第一个
参数: f:Int=>Int 的
是不是很精彩呢?
事实上上述代码还可以进一步简化,因为我们观察到id函数和cube函数的功能非常简单,不需要单独作为
一个函数出现,进一步简化后的代码如下:
code3:
object higherorderfuntion{
def sum(f:Int=>Int,a:Int,b:Int):Int=
if(a>b) 0
else f(a)+sum(f,a+1,b)
def sumInt(a:Int,b:Int):Int = sum(x=>x,a,b)
def sumCube(a:Int,b:Int):Int = sum(x=>x*x*x,a,b)
def sumFac(a:Int,b:Int):Int = sum(fac,a,b)
def fac(a:Int):Int=
if (a==0) 1
else a*fac(a-1)
def main(args:Array[String])={
println(sumInt(1,3))
println(sumCube(1,3))
println(sumFac(1,3))
}
}
code3和code2相比,去掉了id函数和cube这两个函数,并且sumInt和sumCube函数的声明也发生了
一点变化:
def sumInt(a:Int,b:Int):Int = sum(x=>x,a,b) def sumCube(a:Int,b:Int):Int = sum(x=>x*x*x,a,b)
像: x=>x 和 x=>x*x*x 这样的东西是什么呢?在函数式编程里面,这被叫做“function literal”,又称“匿名函数”,
说白了,这也是函数的一种表达方式,只是这个函数没有名字罢了。
code3其实也还有点小毛病,那就是sum函数和fac函数都不是“尾递归”,所以呢,把它们改成尾递归如下:
code4:
object higherorderfuntion{
def sum(f:Int=>Int,a:Int,b:Int):Int={
def loop(a:Int,acc:Int):Int=
if(a>b) acc
else loop(a+1,f(a)+acc)
loop(a,0)
}
def sumInt(a:Int,b:Int):Int = sum(x=>x,a,b)
def sumCube(a:Int,b:Int):Int = sum(x=>x*x*x,a,b)
def sumFac(a:Int,b:Int):Int = sum(fac,a,b)
def fac(a:Int):Int=
{
def loop(a:Int,acc:Int):Int=
if(a==0) acc
else loop(a-1,a*acc)
loop(a,1)
}
def main(args:Array[String])={
println(sumInt(1,4))
println(sumCube(1,4))
println(sumFac(1,4))
}
}
希望把这个事儿说明白了...........
For any questions, feel free to contact me via email or QQ.
Thinking in scala (5)----高阶函数*的更多相关文章
- Thinking in scala (6)----高阶函数----返回一个函数
在Thinking in scala (5)----高阶函数* 里面,我们演示了如何把一个函数作为参数传递给另外一个函数. 在本文里面,我们来演示函数式编程另外一个重要的特性:返回一个函数.首先来看这 ...
- scala面向对象.高阶函数,柯里化,Actor编程简介
1.定义一个类 class Person{ //用val修饰的变量是只读属性,有getter但是没有setter val id ="111" //用var修饰的变量既有getter ...
- Scala中的构造器和高阶函数
构造器 在定义类时可以定义主构造器.主构造器可以同时声明字段. /** * 主构造器 * @author Administrator */ //在scala中,类和方法交织在一起 class Test ...
- Scala - 快速学习08 - 函数式编程:高阶函数
函数式编程的崛起 函数式编程中的“值不可变性”避免了对公共的可变状态进行同步访问控制的复杂问题,能够较好满足分布式并行编程的需求,适应大数据时代的到来. 函数是第一等公民 可以作为实参传递给另外一个函 ...
- spark快速开发之scala基础之5高阶函数,偏函数,闭包
高阶函数 高阶函数就是将函数作为参数或者返回值的函数. object function { def main(args: Array[String]): Unit = { println(test(f ...
- scala高阶函数类型推断什么时候失效?
class TypeInfer(self: Int, other: Int) { def test(num: Int, word: String, fun1: (Int, Int) => Int ...
- Scala高阶函数
1.作为参数的函数 函数可以作为一个参数传入到一个方法当中去 def main(args: Array[String]): Unit = { val myFunc1 =(x:Int) =>{ x ...
- scala中的高阶函数
版权申明:转载请注明出处. 文章来源:http://bigdataer.net/?p=332 排版乱?请移步原文获得更好阅读体验 1.scala中的函数 scala是一门面向对象和函数式编程相结合的语 ...
- Scala高阶函数与泛型
1. Scala中的函数 在Scala中,函数是“头等公民”,就和数字一样.可以在变量中存放函数,即:将函数作为变量的值(值函数). 2. scala中的匿名函数,即没有函数名称的函数,匿名函数常作为 ...
随机推荐
- [转]于Fragment和Activity之间onCreateOptionsMenu的问题
Fragment和Activity一样,可以重写onCreateOptionsMenu方法来设定自己的菜单,其实这两个地方使用onCreateOptionsMenu的目的和效果都是完全一样的,但是由于 ...
- Mesos架构简介
1. 前言 同其他大部分分布式系统一样,Apache Mesos为了简化设计,也是采用了master/slave结构,为了解决master单点故障,将master做得尽可能地轻量级,其上面所有的元数据 ...
- Junit单元测试的简单使用(主要是在spring框架下的项目)
首先是解释什么是单元测试,单元测试是指对于一个大型项目里,对于单一模块或者单一接口的测试. 然后解释为什么要写单元测试,首先对于一个大型的项目,如果你每次都要重启一遍服务器调页面或者接口的bug,那就 ...
- LISTVIEW嵌套GRIDVIEW的一些处理(点击GRIDVIEW的条目,能够显示他在LISTVIEW中的位置)(对这篇文章的优化处理,不每次都new onItemClickListener)
前几天写了点击GRIDVIEW的条目,能够显示他在LISTVIEW中的位置,当时的处理是在ListView的适配器里的GetView方法里每次都new GridView的onItemClickList ...
- hdu_5711_Ingress(TSP+贪心)
题目连接:hdu5711 这题是 HDU 女生赛最后一题,TSP+贪心,确实不好想,看了wkc巨巨的题解,然后再做的 题解传送门:Ingress #include<cstdio> #inc ...
- JSP文件上传--Smartupload组件
把smartupload.jar copy到D:\apache-tomcat-7.0.57\lib下. 创建htm上传文件:smartupload_demo01.htm 由于是上传文件,需要对表单进行 ...
- Android Studio 下载地址【包括国内本地下载】
Android Studio 下载地址,目前最新可下载地址,尽量使用下载工具. Android Studio正式发布,给Android开发者带来了不小的惊喜.但是下载地址却不给力,国内似乎无法正常下载 ...
- 关于java.lang.reflect.InvocationTargetException(jar 包缺少或者冲突)的错误
我在合肥那边运行了的是湖北石首市的项目没有错 可是回武汉之后 运行这个项目 点击这里的时候 就报错java.lang.reflect.InvocationTargetException 不是数据库 ...
- tcp断开连接,4次握手,为什么wireshark 只能抓到3个包?
用wireshark 抓包,看看tcp 断开连接的过程. 以前书上说tcp断开连接,4次握手,可我为什么wireshark 只能抓到3个包? 百度一下,别人也有类似的疑问. [求助]书上和网上的资料 ...
- 转 ORACLE数据库它可以存储 中文 字节或字符
一:因为ORACLE数据库它可以存储字节或字符,例如 CHAR(12 BYTE) CHAR(12 CHAR)的意义是不同的.一般来说默认是存储字节,你可以查看数据库参数NLS_LENGTH_SEMAN ...