接着昨天的文章,再示范一个稍微复杂一点的尾递归tail recursion例子:计算第n个Fibonacci数。Fibonacci数第一、第二个数值分别是0,1,按顺序后面的数值是前面两个数的加合。例如:0,1,1,2,3,5...

 def fib(n: Int): Int = {
@annotation.tailrec
def go(cnt: Int, prev: Int, cur: Int): Int = cnt match {
case m if (m < 0 ) => sys.error("Negative Number Not Allowed!")
case 0 => prev
case c => go(cnt-1,cur, prev + cur)
}
go(n,0,1)
} //> fib: (n: Int)Int
fib(5) //> res52: Int = 5

首先,尾递归是指一个递归函数最后一个语句独立引用了自己。在以上的例子里 go(cnt-1,cur,prev + cur)是最后一条没有增加任何运算的独立语句。我们可以试着约化:

 fib(5)
go(5,0,1)
go(4,1,0+1) = go(4,1,1)
go(3,(0+1),1+(0+1)) = go(3,1,2)
go(2,1+(0+1),(0+1)+(1+(0+1))) = go(2,2,3)
go(1,(0+1)+(1+(0+1)),(1+(0+1))+(0+1)+(1+(0+1))) = go(1,3,5)
go(0,5,8) => 5

正是我们预期的答案。

Scala的函数(function)还是值得提的。函数可以当作标准的对象使用:可以当作另一个函数的输入参数或者结果值。接受函数作为输入参数或者返回另一函数作为结果的函数被称之为高阶函数(high order function)。在Scala编程里匿名函数(anonymous function or lamda function)或函数文本(function literal)的使用也很普遍。用书上的代码样例来示范:

 def formatResult(name: String, n: Int, f: Int => Int) = {
val msg = "The %s of %d is %d."
msg.format(n, f(n))
}

注意formatResult是一个高阶函数,因为它接受一个函数f作为输入参数。这里 Int => Int 是一个类声明,是个函数的类型。看看高阶函数和匿名函数是怎么使用的:

 def main(args: Array[String]): Unit = {
println(formatResult("absolute value", -42, abs))
println(formatResult("factorial", 7, factorial))
println(formatResult("increment", 7, (x: Int) => x + 1))
println(formatResult("increment2", 7, (x) => x + 1))
println(formatResult("increment3", 7, x => x + 1))
println(formatResult("increment4", 7, _ + 1))
println(formatResult("increment5", 7, x => { val r = x + 1; r }))
}

传入函数formatResult的输入参数f可以是一个普通的函数如factorial,abs。也可用函数文本,只要它的类型是Int => Int就可以了。以上匿名函数的各种表述形式可以参考一下Scala语言教程。

泛函编程(3)-认识Scala和泛函编程的更多相关文章

  1. 泛函编程(27)-泛函编程模式-Monad Transformer

    经过了一段时间的学习,我们了解了一系列泛函数据类型.我们知道,在所有编程语言中,数据类型是支持软件编程的基础.同样,泛函数据类型Foldable,Monoid,Functor,Applicative, ...

  2. 备份-泛函编程(23)-泛函数据类型-Monad

    泛函编程(23)-泛函数据类型-Monad http://www.cnblogs.com/tiger-xc/p/4461807.html https://blog.csdn.net/samsai100 ...

  3. scala的面向对象编程

    1.scala的简单编程 2.构造方法 辅助构造函数是在主构造函数没有的情况下,执行的构造函数. 3.object的介绍 4.半生类和半生对象 5.半生的案例程序(半生类可以调用半生) 6.apply ...

  4. Scala链式编程内幕

    package big.data.analyse.scala /** * 链式编程原理 * Created by zhen on 2018/12/16. */ class Computer{def c ...

  5. Scala界面事件处理编程实战详解.

    今天学习了一个Scala界面事件处理编程,让我们从代码出发. import scala.swing._import scala.swing.event._ object GUI_Panel exten ...

  6. 第70讲:Scala界面GUI编程实战详解

    今天又学习了王家林老师的scala学习讲座第70讲,关于scala的界面编程,让我们来初步学习一下scala中界面编程的过程. 信息来源于 DT大数据梦工厂微信公众账号:DT_Spark 关注微信账号 ...

  7. Python黑帽编程2.8 套接字编程

    Python黑帽编程2.8 套接字编程 套接字编程在本系列教程中地位并不是很突出,但是我们观察网络应用,绝大多数都是基于Socket来做的,哪怕是绝大多数的木马程序也是如此.官方关于socket编程的 ...

  8. 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  9. C#编程总结(六)异步编程

    C#编程总结(六)异步编程 1.什么是异步? 异步操作通常用于执行完成时间可能较长的任务,如打开大文件.连接远程计算机或查询数据库.异步操作在主应用程序线程以外的线程中执行.应用程序调用方法异步执行某 ...

  10. 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换

    [源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...

随机推荐

  1. 正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码

    正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码: String regex_name="ssid=\"(.*?)\&quo ...

  2. C++11模板类使用心得

    1.推荐使用std::shared_ptr<TaskT>代替指针TaskT*使用,shared_ptr是一种智能指针,能自主销毁释放内存,在c++11中被引入,在多线程编程中有很大的用处, ...

  3. iOS开发中 workspace 与 static lib 工程的联合使用

    在iOS开发中,其实workspace的使用没有完全发挥出来,最近做了一些研究,也想把之前写过的代码整理下,因为iOS里面的布局方式,交互方式也就那么几种.所以,整理好了之后,更能快捷开发,而且能够形 ...

  4. KendoUI系列:ComboBox

    1.基本使用 1>.创建Input <input id="color" placeholder="Select Color..." /> &l ...

  5. 【WP开发】在手机屏幕点亮时播放声音

    今天说的内容有点流氓,请诸君在开发应用时谨慎使用. 那么,这活儿到底有多流氓呢? 先介绍一下要实现的功能:当用户按电源键(也可以是双击屏幕)点亮手机的屏幕时播放一下短音乐,而且应用程序可以不在前台运行 ...

  6. 什么才是正确的javascript数组检测方式

    前面的话 对于确定某个对象是不是数组,一直是数组的一个经典问题.本文专门将该问题择出来,介绍什么才是正确的javascript数组检测方式 typeof 首先,使用最常用的类型检测工具——typeof ...

  7. BOM之navigator、history、screen对象

    navigator对象 [定义] navigator已经成为识别客户端浏览器的事实标准.下表中列出存在于所有浏览器的属性和方法 [检测插件] 检测浏览器插件是一种最常见的检测例程. [1]对于非IE浏 ...

  8. Android开发之网络

    很多初学Android开发的人员对网络这一点感觉很高大上,现在我就和大家分享一下我的学习心得. 就目前的Android手机来说,可能存在5种网络状态: ----无网络(这种状态可能是因为手机停机,网络 ...

  9. 使用Expression Tree构建动态LINQ查询

    这篇文章介绍一个有意思的话题,也是经常被人问到的:如何构建动态LINQ查询?所谓动态,主要的意思在于查询的条件可以随机组合,动态添加,而不是固定的写法.这个在很多系统开发过程中是非常有用的. 我这里给 ...

  10. 关于orapwd命令entries参数的探究

    今日早上看Oracle官方文档<Administrator's Guide>时,在密码文件章节,关于orapwd命令entries参数的说明如下: This argument specif ...