接着昨天的文章,再示范一个稍微复杂一点的尾递归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. Elasticsearch推荐插件篇(head,sense,marvel)

    安装head head插件可以用来快速查看elasticsearch中的数据概况以及非全量的数据,也支持控件化查询和rest请求,但是体验都不是很好. 一般就用它来看各个索引的数据量以及分片的状态. ...

  2. Atitit  代理与分销系统(1)  子代理 充值总额功能设计概览 sum() groubpy subagt

    Atitit  代理与分销系统(1)  子代理 充值总额功能设计概览 sum() groubpy subagt Keyword 分组与聚合操作. 一个for做分组...里面的做聚合... 数据g操作查 ...

  3. PHP 函数基础

    1.简单函数     函数四要素:返回类型,函数名,参数列表,函数体 function Show(){      echo "hello";}Show();         输出了 ...

  4. 8 步搭建 Node.js + MongoDB 项目的自动化持续集成

    任何事情超过 90 秒就应该自动化,这是程序员的终极打开方式.Automating shapes smarter future. 这篇文章中,我们通过创建一个 Node.js + MongoDB 项目 ...

  5. Java override 和 overload 的区别

    override 是重写(覆盖)了一个方法,用来实现不同的功能,一般是用于子类继承父类时,重写父类的方法的时候. 重写(覆盖)的规则: 1.重写方法的参数列表必须表示与被重写的方法相同,否则不能称为重 ...

  6. 因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 。。。

    因为相同类型的其他实体已具有相同的主键值.在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified&quo ...

  7. 详解JavaScript模块化开发

    什么是模块化开发? 前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来js得到重视,应用也广泛起来了,jQuery,Ajax,Node.Js,MVC,MVVM等 ...

  8. 史上最全github使用方法:github入门到精通

    [初识Github]首先让我们大家一起喊一句“Hello Github”.YEAH!就是这样. 原文 http://www.eoeandroid.com/thread-274556-1-1.htmlG ...

  9. Crumpet – 使用很简单的响应式前端开发框架

    Crumpet 是一个简单的响应式的基于 SASS/SCSS 的响应式前端框架,保持你的 HTML 代码简洁.内置尽量使用占位符选择器,以减少你的 HTML 标记的大小,没有凌乱的 HTML 代码.快 ...

  10. GIF录制神器GifCam

    前几天偶然看到一款神器:GifCam! GifCam是什么? 一款录制gif动画图片的小软件,小到不足一兆. 使用方法(简单到不可思议) 百度 GifCam 下载: 不用安装,直接打开gifcam: ...