Scala函数式编程

尽管Scala是一种混合的面向对象和函数式编程语言,但它强调函数式编程。这就是为什么它是一种强大的语言。如果将Scala作为一种函数式编程语言使用,而不只是把它当作另一种面向对象编程语言来使用的话,用户将从使用中获得更大的利益。

函数式编程(Functional programming, FP)是一种将计算机程序编写为数学函数求值的方法,它避免了状态的改变或数据的突变。这些程序是用纯函数构造的。函数式程序总是声明式的,其中的编程是通过声明和表达式而不是语句来完成的。此外,函数是函数编程语言中的一等公民。

  • 了解函数式编程的基本知识。
  • 将函数式编程与对象和类结合起来。
  • 了解函数式编程特性。
  • 为任何编程任务编写函数式程序。

函数是一等公民

函数是一段可执行代码。函数使程序员能够将大的程序分割成更小的可管理的部分。在函数式编程中,应用程序完全是由函数组装而成的。尽管许多编程语言支持函数的概念,但函数式编程语言将函数视为一等公民。此外,在函数式编程中,函数是可组合的,没有副作用。

Scala将函数范式完美地融合为面向对象范式的关键因素之一是,函数是对象。在函数式编程中,函数是一等公民,意味着函数具有与变量或值相同的状态,可以像使用变量一样使用函数(例如,将函数赋给变量)。

FP允许将一个函数作为输入传递给另一个函数。它允许一个函数作为另一个函数的返回值返回。一个函数可以在任何地方定义,包括在另一个函数内部。它可以定义为未命名的函数字面量,就像字符串字面量一样,并作为输入传递给函数。

函数编程中的函数是可组合的。函数组合是一个数学和计算机科学的概念,将简单的函数组合成复杂的函数。函数可组合性是一种通过将复杂问题分解为一组更简单的子问题来解决复杂问题的有用技术。然后可以为每个子问题编写函数,并在顶级函数中组装在一起。

函数编程中的函数没有副作用。函数返回的结果只依赖于函数的输入参数。函数的行为不会随时间而改变。对于给定的输入,无论调用多少次,它每次都返回相同的输出。换句话说,函数没有状态。它不依赖或更新任何全局变量。没有副作用的功能提供了许多好处。首先,它们可以按任何顺序组合。其次,很容易对代码进行推理。第三,使用这些函数编写多线程应用程序更容易。

不可变的数据结构

函数式编程强调不可变数据结构的使用。纯函数式程序不使用任何可变的数据结构或变量。换句话说,与命令式编程语言(如C/ c++、Java和Python)不同,数据永远不会被就地修改。没有函数式编程背景的人很难想象没有可变变量的程序。在实践中,使用不可变的数据结构编写代码并不困难。

不可变的数据结构提供了许多好处。首先,它们减少了bug。使用不可变数据结构编写的代码很容易推理。此外,函数式语言提供了允许编译器强制不变性的构造。因此,许多错误是在编译时捕获的。

其次,不可变的数据结构使得编写多线程应用程序更加容易。编写一个利用所有核的应用程序并不容易。竞争条件和数据损坏是多线程应用程序的常见问题。使用不可变数据结构有助于避免这些问题。

一切都是一个表达式

在函数式编程中,每条语句都是一个返回值的表达式。例如,Scala中的if-else控制结构是一个返回值的表达式。这种行为不同于命令式语言,命令式语言中,只能在if-else中对一组语句进行分组。

这个特性对于编写没有可变变量的应用程序非常有用。

函数式编程语言分类

函数式编程语言分为两类:

  • 1)纯函数
  • 2)不纯的函数

没有副作用的函数称为纯函数。那么,副作用是什么呢?如果一个函数除了返回一个结果外,还执行以下操作,那么这个函数就有副作用:

  • 修改现有变量。
  • 从文件中读取或写入文件。
  • 修改数据结构(如数组、列表)。
  • 修改对象(在对象中设置字段)。

纯函数的输出仅取决于传递给该函数的输入参数。纯函数总是为相同的输入参数提供相同的输出,而不管调用它的次数是多少。

非纯函数在每次调用时都可以提供不同的输出,函数的输出不仅依赖于输入参数。

下面的函数是一个纯函数的例子:

def sqrt(num:Int):Int = {
  return num * num
}

sqrt(3)

上面代码中定义的函数sqrt,因为它没有副作用,并且输出只依赖于输入参数,所以它被认为是一个纯函数。

注:函数的最后一条语句在Scala中总是一个返回语句。因此,没有必要显式地指定return关键字。

下面是一些典型的纯函数例子:

  • 数学函数,如加法、减法、除法和乘法。
  • String类方法,如length、toUpper和toLower。

以下是一些不纯函数的典型例子:

  • 生成随机数的函数。
  • Date方法如getDate()和getTime(),因为它们根据调用时间返回不同的值。

练习:判断以下函数是属于哪一类?

1. 找出下面函数的类型,并说明原因。

def myFunction(a : Int) :Int ={
    return a
}

2. 找出下面函数的类型,并说明原因。

def myFunction() : Double = {
   var a = Math.random()
   return a
}

3. 下面的函数被称为不纯函数。为什么?

def myFunction(emp : Employee) : Double = {
   emp.setSalary(100000)
   return emp.getSalary()
}

《Flink原理深入与编程实战》