接着昨天的文章,再示范一个稍微复杂一点的尾递归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. Atitit  从 RGB 到 HSL 或 HSV 的转换

    Atitit  从 RGB 到 HSL 或 HSV 的转换 1.1. 从 RGB 到 HSL 或 HSV 的转换公式与原理1 1.2. public static HSV RGB2HSV(Color ...

  2. 1.1.1. Atitit Cocos2d-JS v3.x的问题

    1.1.1. Atitit Cocos2d-JS v3.x的问题   1.1. Api 兼容性 场景切换的api都不兼容了...  删除了比较多的api...可以dep啊.. 1.2. gui布局,, ...

  3. salesforce 零基础学习(三十七) DML及Database方法简单描述

    在apex中通过soql查询可以使用两种方式,使用DML语句或者使用Database的方法. 使用DML语句和使用Database类的方法对于我们来说用的都很多,并且都很常见.对于数据库常见的操作:增 ...

  4. ssh(sturts2_spring_hibernate) 框架搭建之hibernate2

    一.今天要进行解答的是对上次hibernate1进行进一步的完善,这次第一是进一步使用spring注入一个SessionFactory实例,避免了自己new实例:第二是应用数据库池(c3p0). 二. ...

  5. BrowserSync前端调试工具使用

    上次介绍了一款DebugGap移动端调试工具DebugGap推荐.但是这几天使用了之后感觉还是有些不足,尤其是里面的调试工具虽然和Chrome里面的调试长的很像,但是多少有些不同,使用起来还是不太方便 ...

  6. Github快速入门手册

    最近在试用Github,开源的思想也让人觉得把一些经验分享出来是非常好的事情.附件是doc文件,如有需要请注意查收.希望能对你有帮助. GITHUB基于互联网的版本控制快速入门手册 如有不妥,欢迎指正 ...

  7. 文本溢出text-overflow和文本阴影text-shadow

    前面的话 CSS3新增了一些关于文本的样式,其中text-overflow文本溢出和text-shadow文本阴影有些特别.因为它们有对应的overflow溢出属性和box-shadow盒子阴影属性. ...

  8. javase基础复习攻略《九》

    本篇将为大家总结JAVA中的线程机制,谈到线程,大家一定会问线程和进程有什么区别?刚接触进程时我也有这样的疑问,今天就为大家简单介绍一下进程和线程.进程(Process)是计算机中的程序关于某数据集合 ...

  9. ES6入门系列四(测试题分析)

    0.导言 ES6中新增了不少的新特性,来点测试题热热身.具体题目来源请看:http://perfectionkills.com/javascript-quiz-es6/. 以下将一题一题来解析what ...

  10. sizzle源码分析 (4)sizzle 技术总结及值得我们学习的地方

    分析sizzle源码并不是为了去钻牛角尖,而是去了解它的思想,学习下期中一些技术的运用. 1,sizzle中的正则表达式jquery源码中充斥着各种正则表达式,能否看懂其源码的关键之一就是对正则表达式 ...