Scala - 快速学习08 - 函数式编程:高阶函数
函数式编程的崛起
函数是第一等公民
- 可以作为实参传递给另外一个函数
- 可以作为返回值
- 可以赋值给变量
- 可以存储在数据结构里
def greeting() = (name: String) => { s"Hello" + " " + name }
//> greeting: ()String => String
greeting()("World") //> res0: String = Hello World
def greeting2(age: Int) = (name: String) => { s"Hello $name, your age is $age" }
//> greeting2: (age: Int)String => String
greeting2(29)("Anliven") //> res2: String = Hello Anliven, your age is 29
函数类型和值
- Scala语法要求函数的“值”采用“=>”而不是“=”。
- 在Scala中,函数类型的格式为 A => B,表示一个接受类型A的参数,并返回类型B的函数。
def test(x: Int): Int = { x + 1 } //> test: (x: Int)Int
def test1(x: Int) = x + 1 //> test1: (x: Int)Int
val test2: Int => Int = { (x: Int) => x + 1 } //> test2 : Int => Int = testrepl$$$Lambda$8/290658609@c818063
val test3 = { (x: Int) => x + 1 } //> test3 : Int => Int = testrepl$$$Lambda$9/1057941451@75bd9247
def test5(x: Int, y: Int) = x + y //> test5: (x: Int, y: Int)Int
var test6 = (x: Int, y: Int) => x + y //> test6 : (Int, Int) => Int = testrepl$$$Lambda$10/1513712028@3cb5cdba
test6(2, 6)
匿名函数
val myNum: Int => Int = (x: Int) => { x * 2 } //> myNum : Int => Int = testrepl$$$Lambda$3/2093176254@799f7e29
val myNum2 = (x: Int) => x * 2 //> myNum2 : Int => Int = testrepl$$$Lambda$9/804581391@c818063
val myNum3: Int => Int = (x) => x * 2 //> myNum3 : Int => Int = testrepl$$$Lambda$10/1057941451@75bd9247
myNum(3) //> res0: Int = 6
myNum2(3) //> res1: Int = 6
myNum3(3) //> res2: Int = 6
def test1(x: Int): Int = { x * x } //> test1: (x: Int)Int
def test2(x: Int) = x * x //> test2: (x: Int)Int
(x: Int) => x * x //> res0: Int => Int = testrepl$$$Lambda$8/431687835@5ba23b66
val test3 = (x: Int) => x * x //> test3 : Int => Int = testrepl$$$Lambda$9/804581391@c818063
val test4: Int => Int = (x) => x * x //> test4 : Int => Int = testrepl$$$Lambda$10/1057941451@75bd9247
test1(3) //> res1: Int = 9
test2(3) //> res2: Int = 9
test3(3) //> res3: Int = 9
test4(3) //> res4: Int = 9
- 第1行:把匿名函数"(x: Int) => { x * 2 }"定义为一个值,赋值给myNum变量
- 第2行:省略myNum2的类型声明“Int=>Int”,省略匿名函数的表达式花括号
- 第3行:省略x的类型声明,省略匿名函数的表达式花括号
def test1(x: Int, y: Int): Int = { x + y } //> test1: (x: Int, y: Int)Int
def test2(x: Int, y: Int) = x + y //> test2: (x: Int, y: Int)Int
(x: Int, y: Int) => x + y //> res0: (Int, Int) => Int = testrepl$$$Lambda$8/290658609@c818063
var test3 = (x: Int, y: Int) => x + y //> test3 : (Int, Int) => Int = testrepl$$$Lambda$9/1057941451@75bd9247
var test4: (Int, Int) => Int = (x, y) => { x + y }
//> test4 : (Int, Int) => Int = testrepl$$$Lambda$10/2101440631@7dc36524
test1(2, 6) //> res1: Int = 8
test2(2, 6) //> res2: Int = 8
test3(2, 6) //> res3: Int = 8
test4(2, 6) //> res4: Int = 8
闭包
- 如果引用的变量是自由变量,没有绑定具体的值,那么此时这个函数是“开放的”。
- 如果引用的自由变量被绑定具体的值后,不再是“自由变量”,从而构成一个封闭的函数,那么此时这个函数“被关闭”了。
var more = 1 //> more : Int = 1
val addMore = (x: Int) => x + more //> addMore : Int => Int = testrepl$$$Lambda$9/240650537@1cd072a9
addMore(10) //> res0: Int = 11
more = 9
addMore(10) //> res1: Int = 19
def plusStep(step: Int) = (num: Int) => num + step
//> plusStep: (step: Int)Int => Int
val myFunc = plusStep(3) //> myFunc : Int => Int = testrepl$$$Lambda$8/209813603@2f7c7260
println(myFunc(10)) //> 13
高阶函数
def f(x: Int, y: Int) = x + y //> f: (x: Int, y: Int)Int
def operate(f: (Int, Int) => Int) = { f(4, 4) } //> operate: (f: (Int, Int) => Int)Int
operate(f)
//给定两个数区间中的所有整数求和
def sumInts(a: Int, b: Int): Int = {
if (a > b) 0 else a + sumInts(a + 1, b)
} //> sumInts: (a: Int, b: Int)Int
sumInts(1, 5) //> res0: Int = 15 //定义了一个新的函数sum,以函数f为参数
def sum(f: Int => Int, a: Int, b: Int): Int = {
if (a > b) 0 else f(a) + sum(f, a + 1, b)
} //> sum: (f: Int => Int, a: Int, b: Int)Int
//定义了一个新的函数self,该函数的输入是一个整数x,然后直接输出x自身
def self(x: Int): Int = x //> self: (x: Int)Int
//重新定义sumInts函数
def sumInts2(a: Int, b: Int): Int = sum(self, a, b)
//> sumInts2: (a: Int, b: Int)Int
sumInts2(1, 5) //> res1: Int = 15
def sum(f: Int => Int, a: Int, b: Int): Int = {
if (a > b) 0 else f(a) + sum(f, a + 1, b)
} //> sum: (f: Int => Int, a: Int, b: Int)Int
def self(x: Int): Int = x //> self: (x: Int)Int
def square(x: Int): Int = x * x //> square: (x: Int)Int
def powerOfTwo(x: Int): Int = if (x == 0) 1 else 2 * powerOfTwo(x - 1)
//> powerOfTwo: (x: Int)Int
def sumInts(a: Int, b: Int): Int = sum(self, a, b)
//> sumInts: (a: Int, b: Int)Int
def sumSquared(a: Int, b: Int): Int = sum(square, a, b)
//> sumSquared: (a: Int, b: Int)Int
def sumPowersOfTwo(a: Int, b: Int): Int = sum(powerOfTwo, a, b)
//> sumPowersOfTwo: (a: Int, b: Int)Int
println(sumInts(1, 5)) //> 15
println(sumSquared(1, 5)) //> 55
println(sumPowersOfTwo(1, 5)) //> 62
- sumInts函数:求连续整数的和
- sumSquared函数:求连续整数的平方和
- sumPowersOfTwo函数:求连续整数的关于2的幂次和
占位符语法
println("Testing, Scala!") //> Testing, Scala!
val numList = List(-3, -5, 1, 6, 9) //> numList : List[Int] = List(-3, -5, 1, 6, 9)
numList.filter(x => x > 0) //> res0: List[Int] = List(1, 6, 9)
numList.filter(_ > 0) //> res1: List[Int] = List(1, 6, 9)
柯里化
def add(x: Int, y: Int) = x + y //> add: (x: Int, y: Int)Int
add(1, 2) //> res0: Int = 3 def addCurried(x: Int)(y: Int) = x + y //> addCurried: (x: Int)(y: Int)Int
addCurried(1)(2) //> res1: Int = 3 val addOne = addCurried(1)_ //> addOne : Int => Int = TestScala$$$Lambda$8/6738746@7cf10a6f
addOne(2) //> res2: Int = 3
递归
def factorial(n: Int): Int =
if (n <= 0) 1
else n * factorial(n - 1) //> factorial: (n: Int)Int
factorial(5) //> res0: Int = 120
尾递归
package testscala
object TestScala {
def main(args: Array[String]) {
println("Testing, Scala!")
val res = factorial2(5, 1)
println(res)
}
@annotation.tailrec
def factorial2(n: Int, m: Int): Int =
if (n <= 0) m
else factorial2(n - 1, m * n)
}
示例:求整数a到b的相加之和
def sum(f: Int => Int)(a: Int)(b: Int): Int = {
@annotation.tailrec
def loop(n: Int)(acc: Int): Int = {
if (n > b) {
println(s"n=${n},acc=${acc}")
acc
} else {
println(s"n=${n},acc=${acc}")
loop(n + 1)(acc + f(n))
}
}
loop(a)(0)
} //> sum: (f: Int => Int)(a: Int)(b: Int)Int
sum(x => x)(1)(5) //> n=1,acc=0
//| n=2,acc=1
//| n=3,acc=3
//| n=4,acc=6
//| n=5,acc=10
//| n=6,acc=15
//| res0: Int = 15
sum(x => x * x)(1)(5) //> n=1,acc=0
//| n=2,acc=1
//| n=3,acc=5
//| n=4,acc=14
//| n=5,acc=30
//| n=6,acc=55
//| res1: Int = 55
sum(x => x * x * x)(1)(5) //> n=1,acc=0
//| n=2,acc=1
//| n=3,acc=9
//| n=4,acc=36
//| n=5,acc=100
//| n=6,acc=225
//| res2: Int = 225
val square = sum(x => x * x)_ //> square : Int => (Int => Int) = TestScala$$$Lambda$13/757108857@6bdf28bb
square(1)(5) //> n=1,acc=0
//| n=2,acc=1
//| n=3,acc=5
//| n=4,acc=14
//| n=5,acc=30
//| n=6,acc=55
//| res3: Int = 55
Scala - 快速学习08 - 函数式编程:高阶函数的更多相关文章
- 【Python】[函数式编程]高阶函数,返回函数,装饰器,偏函数
函数式编程高阶函数 就是把函数作为参数的函数,这种抽象的编程方式就是函数式编程.--- - -跳过,不是很理解,汗 - ---
- C#函数式编程-高阶函数
随笔分类 -函数式编程 C#函数式编程之标准高阶函数 2015-01-27 09:20 by y-z-f, 344 阅读, 收藏, 编辑 何为高阶函数 大家可能对这个名词并不熟悉,但是这个名词所表达的 ...
- Python进阶:函数式编程(高阶函数,map,reduce,filter,sorted,返回函数,匿名函数,偏函数)...啊啊啊
函数式编程 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计 ...
- (转)Python进阶:函数式编程(高阶函数,map,reduce,filter,sorted,返回函数,匿名函数,偏函数)
原文:https://www.cnblogs.com/chenwolong/p/reduce.html 函数式编程 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数 ...
- [Python3] 035 函数式编程 高阶函数
目录 函数式编程 之 高阶函数 1. 引子 2. 系统提供的高阶函数 3. functools 包提供的 reduce 4. 排序 函数式编程 之 高阶函数 把函数作为参数使用的函数,叫高阶函数 1. ...
- Python实用笔记 (12)函数式编程——高阶函数
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数! Python对函数式编程提供部分支持.由于Python允许使用变量,因此,Python不是纯函数式编程语言. 变量 ...
- 函数式编程 高阶函数 map&reduce filter sorted
函数式编程 纯函数:没有变量的函数 对于纯函数而言:只要输入确定,那么输出就是确定的.纯函数是没有副作用的. 函数式编程:允许把函数本身作为参数传入另一个函数,还允许返回一个函数 高阶函数:一个函数的 ...
- python 函数式编程 高阶函数 装饰器
# -*- coding:gb2312 -*- #coding=utf-8 # 高阶函数 import math def is_sqr(x): y = int(math.sqrt(x)) return ...
- Scala - 快速学习09 - 函数式编程:一些操作
1- 集合类(collection) 系统地区分了可变的和不可变的集合. scala.collection包中所有的集合类 可变集合(Mutable) 顾名思义,意味着可以修改,移除或者添加一个元素. ...
随机推荐
- centos 下安装java
yum安装; 查看yum库中的java安装包 :yum -y list java* 安装需要的jdk版本的所有java程序:yum -y install java-1.8.0-openjdk* 查看j ...
- 在IE浏览器进行编辑操作再展示出现乱码问题
解决方法: ajax传输数据时进行encodeURI编码就可以了 例如: 在其他浏览器中没有进行 encodeURI 直接传输,无问题. 然而,在IE10 和11中进行下面这段代码编辑后,再展示出来就 ...
- 关于学习python的想法
选择学习python,就是一次对自己的挑战.自己之前并没有python的基础,只是学习了一点C语言的知识.对于这个课程了解的不是很多,只是上学期在网上自学了一点,自己也是对这门语言感兴趣,所以这个学期 ...
- C++ vector动态数组
#include<vector>头文件 vector类称作向量类 百度百科的解释:https://baike.baidu.com/item/vector/3330482 我喜欢把知识点拿出 ...
- 团队-爬虫豆瓣top250项目-模块测试过程
模块测试: 项目托管平台地址:https://github.com/gengwenhao/GetTop250.git 模块测试:"获取250排名的全部电影信息"功能,测试方法:手动 ...
- 通过GPLOT过程制作图形
通过GPLOT过程制作图形 和数据报表一样,图形也是展现数据的重要方法,图形的直观效果是数据报表无法替代的.SAS/GRAPH是SAS进行数据可视化展现的重 要组成部分,具有强大的作图功能.可以展现的 ...
- consul搭建
1.准备3台服务器 linux1 192.168.0.101 linux2 192.168.0.102 linux3 192.168.0.103 2.准备向Linux上传文件的工具Winscp 3.去 ...
- CentOS下安装Git
在终端输入命令:yum install git,此时会进行提示安装,输入y, 在这种安装方式下,速度很快(windows系统下下载客户端速度超慢),当出现安装完毕时,就可以了. 安装完毕后输入git ...
- nlp L1
前向最大匹配: 最大匹配出的词必须保证下一个扫描不是词表中的词或词的前缀才可以结束. 正向最大匹配算法:从左到右将待分词文本中的几个连续字符与词表匹配,如果匹配上,则切分出一个词.但这里有一个问题:要 ...
- Ubuntu修改系统时间
在新版的ubuntu中,使用timedatectl 替换了ntpdate来进行时间管理. 1.查看当前时间状态 查看当前时间状态 timedatectl status : res@ubuntu:~$ ...