In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data.
这是来自维基百科给出的定义,简单说就是函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念。
函数式编程中的变量不变性就是指一个函数无论多少线程进行并发调用都不会存在计算结果不一致的情况。因为函数式编程中没有赋值操作,不会保存状态,也就是无状态性。
1. 集成电路芯片上所集成的电路的数目,每隔18个月就翻一番。
2. 微处理器的性能每隔18个月提高一倍,而价格下降一半。
3. 用一个美元所能买到的电脑性能,每隔18个月翻两番。按照摩尔的预测,整个信息产业按照摩尔定律飞速地向前发展着,但近年来,我们却可以发现摩尔定律逐渐地失效了,芯片上元件的尺寸是不可能无限地缩小的,这就意味着芯片上所能集成的电子元件的数量一定会在某个时刻达到一个极限。那么当技术达到这个极限时,我们又该如何适应日益增长的计算需求?电子元件厂商给出了答案:多核。
就这样,函数式编程终于在数十年后,终于走出实验室,来到了真实的生产环境中,无论是冷门的Haskell,Erlang,还是Scala,F#,都是函数式编程成功的典型。
在函数式编程中,函数是基本单位,是第一型,他几乎被用作一切,包括最简单的计算,甚至连变量都被计算所取代。在函数式编程中,变量只是一个名称,而不是一个存储单元,这是函数式编程与传统的命令式编程最典型的不同之处。
函数式编程模型中赋值模型,同一个函数,同一个参数,却会在不同的场景下计算出不同的结果,这是在数学函数中完全不可能出现的情况。f(x) = y ,那么这个函数无论在什么场景下,都会得到同样的结果,这个我们称之为函数的确定性。赋值模型与数学模型的不兼容之处。而函数式编程取消了赋值模型,则使数学模型与编程模型完美地达成了统一。
在面向对象中,我们把事物抽象。而在函数式编程中,我们则是在将函数方法抽象,函数一样是可重用,可置换的抽象单位。
来看个例子,我们在这里举一个求x的n次方的例子,我们用传统的命令式编程来写一下:
def expr(x,n): result = 1 for i in range(1,n+1): result = result * x return result if __name__ == '__main__': print(expr(2,5))这里,一直在对result变量赋值,但在函数式编程中的变量是具有不变性的,那么我们为了保持result的状态,就需要将result作为函数参数来传递以保持状态:
def expr(num,n): if n==0: return 1 return num*expr(num,n-1) if __name__ == '__main__': print(expr(2,5))
这就是递归!
1. 循环是在描述我们该如何地去解决问题。
2. 递归是在描述这个问题的定义。
那么以斐波那契数列为例来看下这两种编程模型。
最常见的递归模型,不采用动态规划来做临时状态的缓存:
def Fib(a): if a==0 or a==1: return 1 else: return Fib(a-2)+Fib(a-1)递归是在描述什么是斐波那契数列,这个数列的定义就是一个数等于他的前两项的和,并且已知Fib(0)和Fib(1)等于1。而程序则是用计算机语言来把这个定义重新描述了一次。
def Fib(n): a=1 b=1 n = n - 1 while n>0: temp=a a=a+b b=temp n = n-1 return b这里则是在描述我们该如何求解斐波那契数列,应该先怎么样再怎么样。
但递归可能产生StackOverflow,而赋值模型呢?
def Fib(a,b,n): if n==0: return b else: return Fib(b,a+b,n-1)如上分析,尾递归其实本质上就是个“伪递归”。
既然我们可以优化,对于大多数的函数式编程语言的编译器来说,对尾递归同样提供了优化,使尾递归可以优化成循环迭代的形式,使其不会造成堆栈溢出的情况。
1. 数学推理
2. 并行程序
函数式编程最适合地还是解决局部性的数学小问题,要让函数式编程来做CRUD,做传统的逻辑性很强的Web编程,就有些免为其难了。
文章大部分内容摘自 函数式编程扫盲篇