函数式编程思想
In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that each return a value, rather than a sequence of imperative statements which change the state of the program or world.
函数式编程(英语:functional programming)或称函数程序设计、泛函编程,是一种编程范式,它将电脑运算视为函数运算,并且避免使用程序状态以及易变对象。其中,λ演算(lambda calculus)为该语言最重要的基础。而且,λ演算的函数可以接受函数当作输入(引数)和输出(传出值)。
重要概念
- 纯函数(pure function)
- 或函数的纯粹性(purity),指没有副作用(side effect)的函数。副作用指的是状态的变化(mutation)。
- 引用透明(referential transparency)
- 对于相同的输入,总是得到相同的输出。如果f(x)的参数和函数体都是引用透明的,则f是纯函数。
- 不变性(immutability)
- 为了获得引用透明性,任何值都不能变化。
- 函数是一等公民(first-class function)
- 一切都是计算,函数式编程中只有表达式,变量和函数都是表达式
- 高阶函数(higher order function)
- 闭包(closure)
- 表达式求值策略
- 严格求值(call by value)
- 非严格求值(call by name)
- 惰性求值(lazy evaluation)
- 递归函数(recursive function)
- 尾递归(tail recursion)
优点
- 生产效率高
- 易于推理(reasoning)
- 适合多核计算、云计算
Scala开发环境
需求
Java | 1.8 |
scala | 2.13.2 |
sbt | 1.3.10 |
scala IDE | 4.7 |
IDE
worksheet
相当于repo,可以直接在IDE中得到结果,交互式。
IDE编译
编写:project--package--scala app
编译运行:run configuration--scala application--已有/new configuration--main class:package_name.app_name--arguments--run
命令行编译
编写:scala app(.scala)
编译运行:cmd--scalac file_name.scala--
scala app中函数的名称要与文件名一致。
Scala的语言基础
变量
val:常量immutable variable
var:变量mutable variable
lazy val:惰性求值的常量
类型体系
数值类型Numeric types
- Byte 1字节
- Short 2字节
- Int 4字节
- Long 8字节
- Float
- Double
低精度可以自由转换到高精度(从上往下),高精度转换到低精度会报错type mismatch,需要隐式转换。
布尔类型Boolean
字符类型Char
单引号
Unit
一般作为函数的返回值。()是unit的文字量。
Null
表示引用值为空,一般不用
Nothing
表示函数异常终止
字符串String
构建于Java的String之上,额外具有字符串插值(interpolation)的特性,类似于Shell语言。
函数与代码块Block
代码块Block
一般用于组织多个表达式,本身也是一个表达式。其最终结果是最后一个表达式的值。
分两种写法
{exp1;exp2;...}
{
exp1
exp2
...
}函数function
def functionName(param:ParamType,...):ReturnType={
//function body:exps
}
if与for
if表达式
if(exp)valA else valB
当没有else时,会返回Nothing。
for comprehension
用于表达循环的一种推导式。
try与match表达式
try表达式
try{}
catch{}
finally{}
类似于Java,try中抛出的异常会被catch所捕捉并抛出(_是通配符),finally中的表达式一定会被执行。
match表达式
exp match{ //主要用于pattern match中
case p1 => val1
case p2 => val2
...
case _ => valn
}
求值策略
- Call By Value
- 对函数实参求值,且仅求值一次
- Call By Name
- 函数实参每次在函数体内被用到时都会求值
通常使用CBV;如果函数形参类型以=>开头,则会使用CBN。
示例
场景1
CBV比CBN少执行一步
场景2
CBV比CBN多执行一步
场景3
由于x是CBV,loop传入之后就会进入死循环。而y是CBN,没有用到y的时候,就不会进入loop。
高阶函数
Scala中,函数是第一等公民,既像普通变量,又具有自己的类型。scala支持
- 把函数作为实参传递给另外一个函数
- 把函数作为返回值
- 把函数赋值给变量
- 把函数存储在数据结构里
函数与匿名函数
函数类型
A => B表示把A映射为B
高阶函数
用函数作为形参或返回值的函数
匿名函数
即函数常量,也称为函数文字量(function literal)
(形参列表)=> {函数体}
柯里化Curried Function
把具有多个参数的函数转换为一条函数链,每个节点上是单一参数。
二者等价
可以通过柯里化定义一些通用函数。
递归与尾递归
递归函数recursive function
在函数式编程中,使用递归实现循环。
递归容易造成堆栈溢出,可以使用尾递归进行优化。
尾递归tail recursive function
所有递归形式的调用都出现在函数的末尾。当编译器检测到一个函数调用是尾递归时,它就覆盖当前的活动记录,而
。
示例****
Immutable Collection
collections-list即List[T]基础
//元素头部拼接list
::
//List拼接
:::
//返回首个
list.head
//返回除首个
list.tail
//返回是否空
list.isEmpty
list高级用法(搭配匿名函数)
//筛选true
list.filter
//转成list
string.toList
//取数直到false
list.takeWhile
list中的map
对list中的元素进行遍历然后映射,结合通配符"_"简化编写。使用flatMap将嵌套的list转为单层。
reduceLeft与flodLeft(规约操作)
reduceLeft
计算过程
代码
foldLeft
计算过程
相较于reduceLeft更通用,确保结果的数据类型为T。
代码
Rang与Stream
整数序列Range
Stream
即lazy list,惰性求值列表,在面对过大列表时,可以避免堆栈溢出。
tuple与map
元组tuple
用于封装函数的返回值
键值对map[k,v]
快速排序案例