Scala 函数式编程

2019-06-06 10:29:52 | 编辑 | 添加

1.什么是 函数式编程?

世上一共有两种编程方式:命令式和声明式。面向对象编程属于命令编程与声明式的结合。函数式编程是声明式,命令式编程:命令“机器”如何去做事情(how),声明式编程:告诉“机器”你想要的是什么(what)。


函数式编程(functional programming)或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算。函数式编程的理论基础是数学中关于函数和值的规则。


如tan(x)=sin(x)/cos(x),可以将函数赋值给变量,也可以将函数作为参数传递给其他函数,还可以将函数作为其他函数的返回值。我们只要确定了参数那么返回值也是确定的。函数式编程是一种声明式风格,我们只要指定做什么而不用指定如何去做。


纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。


函数式编程提倡不可变性、高阶函数和函数组合。这些特性合在一起就能使代码简洁、富有表现力、易于理解和修改。


2.Scala 中的函数式编程

Scala 本质上是一门混合型编程语言,我们既可以使用命令式风格也可以使用函数式风格。当使用Scala 编写代码时,我们可以先使其工作,然后再做优化。对于刚刚接触函数式编程的程序员,他们可以先用命令式风格写好代码,然后再将代码重构成函数式风格。

下面是一段命令式风格的代码,用于从给定日期开始的一系列温度中计算出最大值:

def findMax(temperatures: List[Int]) = {
  var highTemperature = Integer.MIN_VALUE
  for (temperature <- temperatures) {
    highTemperature = Math.max(highTemperature, temperature)
  }
  highTemperature
}


我们创建了可变变量 highTemperature,并在循环中持续修改它。我们必须确保正确地初始化可变变量,并在正确的地方把它们修改为正确的值。

函数式编程是一种声明式风格,我们只要指定做什么而不用指定如何去做。让我们把前面的代码用不带可变参数的函数式风格重写一下。

def findMax(temperatures: List[Int]) = {
temperatures.foldLeft(Integer.MIN_VALUE) { Math.max }
}


上面的代码体现了 Scala 的简洁性和函数式编程风格。我们创建了一个以不可变温度值集合作为参数的函数findMax()。在括号和左大括号之间的=告诉Scala 去推断这个函数的返回类型,在本例中是Int。

在这个函数中,集合的foldLeft()方法在集合的每一个元素上应用函数Math.max()。java.lang.Math 类的max()方法接受两个参数,并算出两者中的较大者。这两个参数在前面的代码中被隐式传递。max()方法的第一个隐式参数是前一次计算出的最高值,而第二个参数是集合在被foldLeft()方法遍历时的当前元素。foldLeft()方法取出调用max()方法的结果,也就是当前最高值,并将它传递到下一次对max()方法的调用中,以便和下一个元素进行比较。foldLeft()方法的参数是最高温度的初始值。



函数式编程中我们并没有修改任何变量或对象。这种不可变的方式是让函数式编程成为并发编程的理想编程风格的关键。在函数式编程中,函数是纯的,它们产生的输出只依赖于它们所接收到的输入,并且它们不会影响任何全局和局部变量的状态,也不会受任何全局或局部的状态影响。