6.1 函数式编程的一些概念

6.1.1 函数式编程的定义

函数式编程又称泛函编程.

是一种编程范型,它将计算机运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。

函数编程语言最重要的基础是λ演算(lambda calculus)。

λ演算中最关键的要素就是函数被当作变量处理,能够参与运算。

函数式编程更加强调执行的结果而非执行过程,倡导利用若干简单的执行单元让计算结果不断演进,抽丝剥茧逐层推导复杂的运算,而不是设计一个复杂的运算过程

函数(function)和过程(procedure)的区别

函数和过程都会进行一系列的运算, 但是他们两个之间还是有一定的区别的.

function 通过运算返回一个值,而 procedure 只执行一段代码,没有返回值

6.1.2 什么是纯函数(Pure Function)

函数式编程中都喜欢追求纯函数, 那么什么样的函数才是纯函数?

我们将满足下面 2 个条件的函数称为纯函数:

  1. 函数不会产生side effect(副作用)

    除了返回值外,不修改程序的外部状态(比如全局变量、入参)

    常见的副作用:

    • 改变外部变量的值
    • 向磁盘中写入数据
    • 将页面上的一个按钮设置为可点击,或者不可点击
  2. 引用透明 指的是函数的运行不依赖于外部变量或“状态”,只依赖于输入的参数,任何时候只要参数相同,调用函数所得到的返回值总是相同的。

    天然适应并发编程,因为调用函数的结果具有一致性,所以根本不需要加锁,也就不存在死锁的问题。

    • 满足Referential Transparency的函数可以将可以将用函数计算的结果替换表达式本身,而不影响程序的逻辑。

    • 给定指定的参数,在任何时候返回的值都是相同的。不受其他外部条件影响。

纯函数

def sum(a,b): return a+b

不是纯函数

int sum = 0
def plus(a,b){
  sum = a + b  // 修改了外部变量的值, 所以不是纯函数
  return sum
}

6.1.3 函数式编程的特点

正如封装、继承和多态是面向对象编程的三大特性。函数式编程也有自己的语言特性:

  1. 数据不可变(immutable data):

    变量只赋值一次,如果想改变其值就创建一个新的变量。

  2. 函数是第一公民(first class method)

    函数可以像普通变量一样去使用。

    函数可以像变量一样被创建,修改,并当成变量一样传递,返回或是在函数中嵌套函数。

  3. 引用透明(referential transparency)

  4. 尾递归(tail call optimization)

    函数调用要压栈保存现场,递归层次过深的话,压栈过多会产生性能问题。

    所以引入尾递归优化,每次递归时都会重用栈,提升性能。


6.1.4 函数式编程的好处

  1. 当我们按照函数式编程的思想编写程序时,程序具有天然的模块属性,因为实现的函数为pure function,你可以任意组合这些 pure function。

  2. pure function 不会产生side effect,不需要对外部的状态产生顾虑。

  3. Memoization 优化

    满足引用透明的表达式(包括任意纯函数调用)满足这样一个特点,就是任意两次调用只要输入相同,其结果总是不变的。

    于是可以将第一次的计算结果缓存起来,遇到下一次执行时直接替换,依然能保证程序的正确性。这种优化方法称为Memoization。

  4. 延迟求值 ( Lazy Evaluation ) 提升性能 延迟求值是指表达式不在它被绑定到变量时就立即求值,而是在该值被用到的时候才计算求值。

    很显然,延迟求值的正确性需要纯函数的性质来保证——即在输入参数相同的情况下,无论什么时候被执行,结果总是不变的。

    延迟求值有利于程序性能的提升。

  5. 可以使用 currying(函数) 技术进行函数封装 curryiny 将接受多个参数的函数变换成接受其中部分参数,并且返回接受余下参数的新函数。(维基百科中的定义是接受一个单一参数的新函数,然而现实中 currying 技术的涵义被延伸了。)

    后面课程细讲


6.1.5 面向对象和函数编程的结合

Scala 把面向对象编程和函数式编程完美的融合在一起.
  1. 函数式编程是从编程方式(范式)的角度来谈的,可以这样理解函数式编程把函数当做一等公民,充分利用函数支持的函数的多种使用方式.

    比如:在 Scala 当中,函数是一等公民,像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个变量. 函数的创建不用依赖于类或者对象,而在Java当中,函数的创建则要依赖于类、抽象类或者接口。

  2. 面向对象编程是以对象为基础的编程方式。

  3. 在 scala 中函数式编程和面向对象编程完美融合在一起了。


6.1.6 函数和方法的区别与联系

在 scala 中,方法和函数几乎可以等同(比如他们的定义、使用、运行机制都一样的),只是函数的使用方式更加的灵活多样。

还有一点: 函数可以作为参数传递, 方法不行. 后面细讲

Copyright © 尚硅谷大数据 2019 all right reserved,powered by Gitbook
该文件最后修订时间: 2019-05-18 15:03:20

results matching ""

    No results matching ""