泛函编程(3)-认识Scala和泛函编程

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

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

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

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

正是我们预期的答案。

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

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

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

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

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

时间: 2024-08-01 09:27:09

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

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

  经过了一段时间的学习,我们了解了一系列泛函数据类型.我们知道,在所有编程语言中,数据类型是支持软件编程的基础.同样,泛函数据类型Foldable,Monoid,Functor,Applicative,Traversable,Monad也是我们将来进入实际泛函编程的必需.在前面对这些数据类型的探讨中我们发现: 1.Monoid的主要用途是在进行折叠(Foldable)算法时对可折叠结构内元素进行函数施用(function application). 2.Functor可以对任何高阶数据类型F[

泛函编程(15)-泛函状态-随意数产生器

  对于OOP程序员来说,泛函状态变迁(functional state transition)是一个陌生的课题.泛函状态变迁是通过泛函状态数据类型(functional state)来实现的.State是一个出现在泛函编程里的类型(type).与其它数据类型一样,State同样需要自身的一套泛函操作函数和组合函数(combinators),我们将在以下章节中讨论有关State数据类型的设计方案.      在正式介绍State类型前,我们先从随意数产生器(RNG: Random Number

c语言-“熟悉win32环境下编程”其中的win32环境下编程是不是就是c/c++那个编程环境啊?

问题描述 "熟悉win32环境下编程"其中的win32环境下编程是不是就是c/c++那个编程环境啊? 如题?"熟悉win32环境下编程"其中的win32环境下编程是不是就是c/c++那个编程环境啊?多谢 解决方案 字面意思很明白了,win32环境编程,首先是windows 其次是32位机,为什么要和c++关联起来呢? 解决方案二: C/C++可以写 Win32 的程序,也可以写 Linux 的程序.这里的 Win32,主要是指 Win32 API,如 windows

096_《Delphi5高级编程丛书之二:GUI编程》

<Delphi5高级编程丛书之二:GUI编程> Delphi 教程 系列书籍 (096) <Delphi5高级编程丛书之二:GUI编程> 网友(邦)整理 EMail: shuaihj@163.com 下载地址: Part1 Part2 Part3 Part4 作者: 徐新华 出版社: 人民邮电出版社 书号: 出版日期:2000年4月 开本: 787*1092 1/16 页码: 496 版次: 2000年4月第一版第一次印刷 内容简介 本书全面深入地介绍了如何运用 Delphi 5进

函数式接口、默认方法、纯函数、函数的副作用、高阶函数、可变的和不可变的、函数式编程和 Lambda 表达式 - 响应式编程 [Android RxJava2](这到底是什么)第三部分

本文讲的是函数式接口.默认方法.纯函数.函数的副作用.高阶函数.可变的和不可变的.函数式编程和 Lambda 表达式 - 响应式编程 [Android RxJava2](这到底是什么)第三部分, 太棒了,我们又来到新的一天.这一次,我们要学一些新的东西让今天变得有意思起来. 大家好,希望你们都过得不错.这是我们的 RxJava2 Android 系列的第三篇文章. 第一部分 第二部分 在这篇文章中,我们将讨论函数式的接口,函数式编程,Lambda 表达式以及与 Java 8 的相关的其它内容.这

《嵌入式C编程:PIC单片机和C编程技术与应用》一第3章预编译指令3.1 标准预编译指令

本节书摘来自华章出版社<嵌入式C编程:PIC单片机和C编程技术与应用>一书中的第3章,第3.1节,作者 [美]马克·西格斯蒙德(Mark Siegesmund),更多章节内容可以访问"华章计算机"公众号查看 第3章 Embedded C Programming: Techniques and Applications of C and PIC MCUS 预编译指令 编译器对C程序的处理可以明确地分为两步.第一步由预编译器完成.以#开头的预编译指令可能会影响编译器设置或者进行

《嵌入式C编程:PIC单片机和C编程技术与应用》一1.8 时间

本节书摘来自华章出版社<嵌入式C编程:PIC单片机和C编程技术与应用>一书中的第1章,第1.8节,作者 [美]马克·西格斯蒙德(Mark Siegesmund),更多章节内容可以访问"华章计算机"公众号查看 1.8 时间 在delay_ms中,ms表示毫秒(milliseconds).编程中常用的时间单位有: ns ?nanosecond(纳秒) ??0.000?000?001s μs ?microsecond(微秒) 0.000?001s ms millisecond(毫

《嵌入式C编程:PIC单片机和C编程技术与应用》一第1章C语言概述和程序结构1.1 C源代码

本节书摘来自华章出版社<嵌入式C编程:PIC单片机和C编程技术与应用>一书中的第1章,第1.1节,作者 [美]马克·西格斯蒙德(Mark Siegesmund),更多章节内容可以访问"华章计算机"公众号查看 第1章 Embedded C Programming: Techniques and Applications of C and PIC MCUS C语言概述和程序结构 1.1 C源代码 下面是一段C语言源代码: 这段代码初看起来可能会觉得难以理解,但读完本书并完成书中

《嵌入式C编程:PIC单片机和C编程技术与应用》一1.4 C预编译指令

本节书摘来自华章出版社<嵌入式C编程:PIC单片机和C编程技术与应用>一书中的第1章,第1.4节,作者 [美]马克·西格斯蒙德(Mark Siegesmund),更多章节内容可以访问"华章计算机"公众号查看 1.4 C预编译指令 预编译是C语言中一个非常有意思的特性.预处理使用工具(预处理器)在编译前先扫描一遍代码,并对代码做出相应的修改从而生成用来编译的代码.预编译指令由#开始,占用一整行.在第3章中将会详细介绍它.在上面的例子中,#include指令将文件(e3.h)的

《嵌入式C编程:PIC单片机和C编程技术与应用》一1.5 函数

本节书摘来自华章出版社<嵌入式C编程:PIC单片机和C编程技术与应用>一书中的第1章,第1.5节,作者 [美]马克·西格斯蒙德(Mark Siegesmund),更多章节内容可以访问"华章计算机"公众号查看 1.5 函数 接下来,我们看到了一个函数定义"main".所有程序都需要有一个main()函数,也就是主函数.这是程序开始执行的地方.在本书中,当提到函数名时,我们都会在它的名字后面跟上(),表示这是个函数. 函数名前的void表示此函数的类型是vo