高阶函数是函数式编程里面一个非常重要的特色,所谓的高阶函数,就是以其它函数作为参数的函数。

下面以一个小例子演示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)----高阶函数*的更多相关文章

  1. Thinking in scala (6)----高阶函数----返回一个函数

    在Thinking in scala (5)----高阶函数* 里面,我们演示了如何把一个函数作为参数传递给另外一个函数. 在本文里面,我们来演示函数式编程另外一个重要的特性:返回一个函数.首先来看这 ...

  2. scala面向对象.高阶函数,柯里化,Actor编程简介

    1.定义一个类 class Person{ //用val修饰的变量是只读属性,有getter但是没有setter val id ="111" //用var修饰的变量既有getter ...

  3. Scala中的构造器和高阶函数

    构造器 在定义类时可以定义主构造器.主构造器可以同时声明字段. /** * 主构造器 * @author Administrator */ //在scala中,类和方法交织在一起 class Test ...

  4. Scala - 快速学习08 - 函数式编程:高阶函数

    函数式编程的崛起 函数式编程中的“值不可变性”避免了对公共的可变状态进行同步访问控制的复杂问题,能够较好满足分布式并行编程的需求,适应大数据时代的到来. 函数是第一等公民 可以作为实参传递给另外一个函 ...

  5. spark快速开发之scala基础之5高阶函数,偏函数,闭包

    高阶函数 高阶函数就是将函数作为参数或者返回值的函数. object function { def main(args: Array[String]): Unit = { println(test(f ...

  6. scala高阶函数类型推断什么时候失效?

    class TypeInfer(self: Int, other: Int) { def test(num: Int, word: String, fun1: (Int, Int) => Int ...

  7. Scala高阶函数

    1.作为参数的函数 函数可以作为一个参数传入到一个方法当中去 def main(args: Array[String]): Unit = { val myFunc1 =(x:Int) =>{ x ...

  8. scala中的高阶函数

    版权申明:转载请注明出处. 文章来源:http://bigdataer.net/?p=332 排版乱?请移步原文获得更好阅读体验 1.scala中的函数 scala是一门面向对象和函数式编程相结合的语 ...

  9. Scala高阶函数与泛型

    1. Scala中的函数 在Scala中,函数是“头等公民”,就和数字一样.可以在变量中存放函数,即:将函数作为变量的值(值函数). 2. scala中的匿名函数,即没有函数名称的函数,匿名函数常作为 ...

随机推荐

  1. HDU 4635 Strongly connected(强连通分量缩点+数学思想)

    题意:给出一个图,如果这个图一开始就不是强连通图,求出最多加多少条边使这个图还能保持非强连通图的性质. 思路:不难想到缩点转化为完全图,然后找把它变成非强连通图需要去掉多少条边,但是应该怎么处理呢…… ...

  2. stray '/241' in program 错误

    意思是c/c++中的编译错误. 该错误是指源程序中有非法字符,需要去掉非法字符.一般是由于从别的地方粘贴过来造成的. 方法:1.把所粘的文字放到记事本里就行了 2.把出错行的空格删掉重新打一下试试.

  3. 忘了SA密码的SQL SERVER

    [暂时还未验证] SQL2008  如果 本地连接登录补上,也忘了Sa等管理账号的密码,可以通过单用户连接的方式登录 http://msdn.microsoft.com/zh-cn/library/m ...

  4. 博弈论最简单例子TacTicToe

    博弈论是人工智能中的一个分支.顾名思义就是下棋的算法.当然引申出来的应用可能不止用来下棋,也可以用来做游戏或者模拟战争策略等. 博弈的基本算法也是模拟人的思维,比如当自己下子时遍历所有可能寻求最有利步 ...

  5. DedeCMS中实现在顶层banner中显示自定义登录信息

    一.需求描述 dedeCMS自带的模板中有互动中心模块,如下图所示: 由于会员登陆对我来说不是网站的重要模块且默认DedeCMS的会员中心模块的初始化很慢,常会显示“正在载入中,请稍候...”, 所以 ...

  6. hdu_5719_Arrange(脑洞题)

    题目连接:hdu_5719_Arrange 题意: 给你1-n这 n个数,设一个排列的第i个数为Ai, Bi为A1到Ai的最小值,Ci为C1到Ci的最大值,问你有多少种排列方式,然后输出取模后的答案 ...

  7. 【转】使IFRAME在iOS设备上支持滚动

    原文链接: Scroll IFRAMEs on iOS原文日期: 2014年07月02日 翻译日期: 2014年07月10日翻译人员: 铁锚 很长时间以来, iOS设备上Safari中超出边界的元素将 ...

  8. JavaBean-- 设置和取得属性

    <jsp:setProperty>标签一共有4种使用方法: 自动匹配:<jsp:setProperty name="实例化对象的名称(id)" property= ...

  9. 几种在shell命令行中过滤adb logcat输出的方法

    我们在Android开发中总能看到程序的log日志内容充满了屏幕,而真正对开发者有意义的信息被淹没在洪流之中,让开发者无所适从,严重影响开发效率.本文就具体介绍几种在shell命令行中过滤adblog ...

  10. SQL求解两个时间差

    sql 求解两个时间差 SELECTDATEDIFF( Second, '2009-8-25 12:15:12', '2009-9-1 7:18:20') --返回相差秒数 SELECTDATEDIF ...