函数式编程(英语:Functional programming)或者函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。函数编程语言最重要的基础是λ演算(lambda calculus)。而且λ演算的函数可以接受函数当作输入(引数)和输出(传出值)。
从具体的编程语言实现来来看,数据的不变性,一等函数,高等函数,lambda运算,闭包,惰性求值。另外函数式编程大量使用递归,但是递归效率很低,因此出现了尾递归来优化。除了这些通用的特性以外各个编程语言还实现了自己独有的函数式编程特性。下面就先从通用的开始介绍,然后在介绍各个编程语言独有的特性。
数据的不变性:数据不变性指的是一个编程语言中的数据类型一旦分配空间并初始化,那么他的内容就不可以再改变。由于这儿讨论的是都是面向对象的编程对象,而面向对象的编程语言中可以有两种类型的”变“:引用改变和对象属性的改变。引用改变非常简单,Java的final和C++的const都可以实现。因此这儿代表的是对象属性的不可变,在函数式编程里面强调避免使用程序状态以及易变对象。因为这样就不用考虑对象共享的问题了,一个对象可以任意共享,因为知道这个对象会保持原样。
Scala中的不变:Scala中提供了var和val用来控制引用的不变性,var表示变量,val表示不变。注意他们就相当于Java中的final关键字,并没有保证底层对象的不可变。例如:
import scala.collection.mutable.Map
val treasureMap = Map[Int, String]()
treasureMap += (1 ->"Go toisland.")
treasureMap += (2 ->"Find big X onground.")
treasureMap += (3 ->"Dig.")
另外注意:如果对象的每一个属性都用val声明的话,那么就可以实现对象内容的不变。
Scala的类库中提供了两种集合类型:一种是不可变的。在scala.collection.immutable包中,这是默认的,也就是说如果上面的代码没有显式导入可变的Map类那么创建的Map就是不可变的。第二中是可变的集合类型,在scala.collection.mutable。他们的特质,英文trait(类似于Java中的接口)在scala.collection中。
Ruby中的不变:Ruby并没有提供引用层次的不可变,但是Ruby的freeze方法就是把对象冻结,这样任何改变都会抛出异常,我本人觉得这种方法较灵活但是也容易引起不必要的麻烦,因为我不知道这个对象为什么突然就不能改变了,追踪起来也比较麻烦。例如,
Array = [“ssj”,20,”ssh”,12]
Array<<”ssjssh”
Array.freeze =
Array<<”sshssj”//RuntimeError:can’t modify frozen Array
另外:Erlang使用的也是引用的模型,它的引用和值都不可变。因此可以认为Erlang的变量完全不可变。
Ruby使用冻结的方法可以得到不变的值,但是没有办法来阻止引用不可变。
Scala的引用不可变非常容易实现,但是值不变需要类的封装来实现,这样它的机制比较难以实现,细节也较多。
相比较而言,Erlang不变量最简单最易用,Ruby的使用比较Scala来的简单。