函数式编程基础
- 函数定义/声明
- 函数运行机制
- 递归//难点 [最短路径,邮差问题,迷宫问题, 回溯]
- 过程
- 惰性函数和异常
函数式编程高级
- 值函数(函数字面量)
- 高阶函数
- 闭包
- 应用函数
- 柯里化函数,抽象控制...
函数式编程定义
注释: 我想写函数点
一.什么是函数式编程?
函数式编程思想来源于伟大数学家阿隆佐设计的lambda验算,是指用函数来解决与计算相关的几乎所有问题。
和面向对象编程以对象为模块的思想一样,函数式编程是以函数为核心来组织模块的,这种组织方式更有利于写出模块化的代码。
二.函数式编程的基本准则
1.函数是"一等公民"
所谓一等公民是指,函数与我们平时所使用的其他数据类型地位一样:
(1)可以赋值给一个变量
(2)可以作为参数进行传递
(3)可以作为别的函数的返回值
(4)函数的创建不用依赖于类或者对象,而是和对象同级别,或者说函数本身就是一种对象。(python 就是这样)
在学习Scala中将方法、函数、函数式编程和面向对象编程明确一下:
2.尽量写"纯函数"
所谓纯函数是指,给定相同输入总能得到相同输出的函数。纯函数需要同时满足下面两个条件:
(1)函数的结果只依赖于输入的参数且与外部变量和环境无关——只要输入相同,返回值总是不变的。
(2)除了返回值外,不修改程序的外部状态(比如全局变量、入参)——FP中所有的变量都是final的,这样设计的原因是因为lambda验算只关心计算的结果而不关心每个状态的值。
总之,纯函数,就是指这样一个函数,对于相同的输入,永远得到相同的输出,它不依赖外部环境,也不会改变外部环境。如果不满足以上几个条件那就是非纯函数。
scala函数
scala函数的定义
基本语法
def 函数名 ([参数名: 参数类型], ...)[[: 返回值类型] =] {
语句...
return 返回值
}
- Scala语法中任何的语法结构都可以嵌套其他语法结构(灵活),即:函数中可以再声明/定义函数,类中可以再声明类 ,方法中可以再声明/定义方法
- 函数声明关键字为def (definition)
- [参数名: 参数类型], ...:表示函数的输入(就是参数列表), 可以没有。 如果有,多个参数使用逗号间隔
- 函数中的语句:表示为了实现某一功能代码块
- 函数可以有返回值,也可以没有
- 返回值形式1: :T= 返回值类型 是T
- 返回值形式2: 直接 = 表示返回值类型不确定,使用类型推导完成
- 返回值形式3: Unit表示没有返回值,即使有return也 不生效
- 如果没有return ,默认以执行到最后一行的结果作为返回值
函数返回值:
- 返回值列表的数据类型可以是值类型和引用类型。
- Scala中的函数可以根据函数体最后一行代码自行推断函数返回值类型。那么在这种情况下,return关键字可以省略
- 因为Scala可以自行推断,所以在省略return关键字的场合,返回值类型也可以省略
- 如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,这时要明确写成 : 返回类型 = ,当然如果你什么都不写,即使有return 返回值为()
- 如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值
- 如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为Any)
- 递归函数未执行之前是无法推断出来结果类型,在使用时必须有明确的返回值类型
案例参数:
def fun1(i: Int,j: Int): Int = {
return 1
}
def fun2(i: Int,j: Int): Int = {
1
}
//自动推导
def fun3(i:Int)={
1
}
def fun4(i:Int):Unit={
return 1 //依旧返回()
}
函数传参:
- 函数的形参列表可以是多个, 如果函数没有形参,调用时可以不带()
- 形参列表的数据类型可以是值类型和引用类型。
- 默认传参:Scala函数的形参,在声明参数时,直接赋初始值(默认值),这时调用函数时,如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值。
- 如果函数存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆盖默认值,还是赋值给没有默认值的参数,就不确定了(默认按照声明顺序[从左到右])。在这种情况下,可以采用带名参数
- 不定长传参:Scala函数支持可变参数的不定长传参,这个 参数 是个集合, 通过 for循环 可以访问到各个值。
- 默认传参和不定长传参不可以混用,否则报错;
- scala 函数的形参默认是val的,因此不能在函数中进行修改.
函数的调用
函数的调用机制
函数的递归调用
过程
基本介绍
将函数的返回类型为Unit的函数称之为过程(procedure),如果明确函数没有返回值,那么等号可以省略
案例说明:
注意:
注意区分: 如果函数声明时没有返回值类型,但是有 = 号,可以进行类型推断最后一行代码。这时这个函数实际是有返回值的,该函数并不是过程。(这点在讲解函数细节的时候讲过的.)
开发工具的自动代码补全功能,虽然会自动加上Unit,但是考虑到Scala语言的简单,灵活,最好不加.
惰性函数
惰性计算
惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元素,无需预先计算它们,这带来了一些好处。
- 可以将耗时的计算推迟到绝对需要的时候。
- 可以创造无限个集合,只要它们继续收到请求,就会继续提供元素。
函数的惰性使用能够得到更高效的代码。Java 并没有为惰性提供原生支持,Scala提供了。
介绍
当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数,在Java的某些框架代码中称之为懒加载(延迟加载)。
object HelloScala {
def main(args: Array[String]): Unit = {
//惰性加载 这里并没有直接sum()
lazy val res = sum(10, 20)
println("-----------------")
println("res=" + res) //在要使用res 前,才执行 }
}
def sum(n1: Int, n2: Int): Int = {
println("sum() 执行了..")
return n1 + n2
}
}
注意:
lazy 不能修饰 var 类型的变量
不但是 在调用函数时,加了 lazy ,会导致函数的执行被推迟,我们在声明一个变量时,如果给声明了 lazy ,那么变量值得分配也会推迟。
大多数人都以为是才智成就了科学家,他们错了,是品格。---爱因斯坦