目录 第6章 scala 函数式编程
函数式编程优势
函数式编程主要可以为当前面临的三大挑战提供解决方案
- 并发需求,函数式编程提供了很好的并发性,可以对应用进行水平扩展,并提供了对抗服务器故障的能力
- 多线程程序的大部分难点在于对公共的可变状态进行访问时同步问题。如果去掉了公共状态的可变性,这个问题将不复存在。引用透明的函数和值不可变性的结合,使得函数式编程
- 处理大数据的需求
- 可以有效的减少程序bug的数量
什么是函数式编程
函数式编程:是一种编程方式,将电脑的运算当成函数的运算,一个函数的参数是另一个函数名
函数式编程的特点
- 可以在任何地方调用函数,并确信其行为与上下文无关,每次的行为都能够确保相同。由于没有任何全局对象被修改,对函数的并发调用也是安全可靠的,不需要任何线程安全的编写技巧
- 可以用表达式所计算得出的值替换表达式本身。例如:sin(pi/2) = 1 成立,只要sin 函数是纯函数,代码分析器如编译器或者运行时的虚拟机就可以将函数调用sin(pi/2) 替换为1,而不会引入任何错误。返回Unit 的函数只能执行带副作用的操作,它必须在某处对可变状态做修改。例如:调用println或printf 去打印the world字符串函数,它将某个I/O相关状态修改为the world
函数是第一等级的值,就像数据变量的值一样。可以从函数中组合成新的函数(如:tan(x)=sin(x)/cos(x)),可以将函数赋值给变量,也可以将函数作为参数传递给其他函数,还可以将函数作为返回值。
高阶函数:将其他函数作为本函数的参数。如集合类型的map方法,map方法的参数是一个函数,该函数对集合中的每个元素进行操作。高阶的纯函数被称为粘合剂,它们可以将灵活、细粒度的代码块和粒度更大,更复杂的程序很好的组合在一起,使用较少的代码完成复杂逻辑的例子
- 变量不可变,在函数式编程中变量被认为是不可变的,是val类型。如果无法修改变量,就无法使用循环变量,也不能通过方法的调用修改对象的状态,不能执行输入和输出操作。显然,我们不能永远使用纯函数,没有了输入和输出,计算机将没有任何意义。实践中的函数式编程对何时执行可变操作,什么时候只调用纯函数做了明确的界定
- 纯函数(Pure Function)是这样一种函数——输入输出数据流全是显式(Explicit)的。
- 显式(Explicit)的意思是,函数与外界交换数据只有一个唯一渠道——参数和返回值;函数从函数外部接受的所有输入信息都通过参数传递到该函数内部;函数输出到函数外部的所有信息都通过返回值传递到该函数外部。
- 如果一个函数通过隐式(Implicit)方式,从外界获取数据,或者向外部输出数据,那么,该函数就不是纯函数,叫作非纯函数(Impure Function)。
- 并不是说函数式编程无状态,可以用新的对象或新开的栈空间来表示状态的修改。即:函数调用,并返回你要的值。
def factorial(i: Int): Long = {
def fact(i: Int,accumulator: Int) : Long = {
if (i <= 1) accumulator
else fact(i-1,i*accumulator)
}
fact(i,1)
}
(0 to 5) foreach( i=> println(factorial(i)))
// 使用递归函数计算阶乘,对计算结果的每次更新被压倒栈上,而不是直接修改栈中的值
- 纯函数与值不可变性极大地降低了bug出现的概率。致命的bug大多来源于可变状态。
- 如果要修改不可变对象,只能在需要改变的时候先复制一份,再进行修改。函数式编程通过共享对象中未修改部分使得复制的开销最小化
- 函数式编程的惰性求值:求值操作推迟到需要用到的时候。scala默认的求值是立即求值或者严格求值。只有scala的Stream 类型才是惰性求值。由于惰性求值的效率不高,而且求值的结果很难预测。Haskell 默认是惰性求值