浅析函数式编程与命令式编程的区别(一)计算模型的区别
讨论之前,这里先对概念进行一下界定。这里的命令式编程语言泛指所有把修改变量的值当作最基本计算方式的语言,函数式编程语言指把一个程序的输出定义为其输入的数学函数的语言,纯函数式编程没有内部状态的概念,也没有副作用。
要理解各种程序设计模型之间的不同,先考虑一下它们各自所基于的计算模型会有所帮助。命令式和函数式模型是从数学家图灵、丘奇、克林、波斯特等人在20世纪30年代所做工作的基础上成长起来的。这些先驱者分别基于自动机、符号操作、递归函数、和组合学开发出了几种差异巨大的形式化模型。现在人们已经证明这些不同的理论具有相同能力:任何一种模型里可以计算的东西,在另一种模型里也能计算。这些形式化模型都可以看作计算机的数学模型。
图灵的计算模型就是图灵机,这是一种类似于有穷自动机或下推自动机的机器,但具有访问一条无界的存储“带子”上任意单元的能力。图灵机通过不断修改其存储带上的单元值,以一种命令式的方式进行计算,就像高级命令式语言通过修改变量的值做计算一样。换句话说,图灵机就是命令式语言的计算模型,通过修改变量的值来影响后续的计算。也就是说命令式语言内部是有状态的,计算的过程也就是状态转换的过程,改变状态的方式就是通过赋值等方式改变存储器中变量的值。
丘奇的计算模型是lambda 演算,基于带参表达式的概念。它包括一条变换规则(变量替换)和一条函数定义方式。在lambda演算中,每个表达式都代表一个只有单独参数的函数,这个函数的参数本身也是一个只有单一参数的函数,同时,函数的值是又一个只有单一参数的函数。Lambda演算强调的是变换规则的运用,而非实现它们的具体机器。lambda 演算就是函数式语言的计算模型,函数式语言的计算的主要方式是将函数作用与给定参数上,在函数式语言中可以没有命令式语言所必需的变量和赋值语句,一切(包括程序本身)都是从输入到输出的函数。
从效果上看,任何计算机程序都可以看作是对某命题的一个构造性证明,即给它任何合适的输入,都存在着某种按特定的所期望的方式与之相关的一些输出。下面举个列子来显示一下命令式语言的程序员和函数式语言的程序员对同一个问题的不同解决办法:计算a,b两个整数的最大公约数
命令式语言的程序员:
要计算a和b的gcd,先检查a和b是否相等,如果相等就打印他们之中一个并且结束;否则就把较大的那个换成他们的差,并重复这以工作。
函数式语言的程序员:
当a和b相等时,它们的gcd就定义为a;当a和b不相等时去计算c和d的gcd,其中c是两个数较小的一个,d是两个数的差。要计算给定一对数的gcd,请展开并简化上述定义直到它结束。
作者曰:以前我一直以为命令式语言代表的计算机的硬件结构(或者说是机器本质),而函数式语言代表的计算机的数学本质。但是后来我才发现自己错了,其实从某种意义说,它们都代表了计算机的数学本质(当然命令式语言还有明显硬件结构特征),他们都有着自己的计算模型,只是不一样而已,而且计算机的数学模型也不止一种。虽然,命令式语言的出发点都是冯诺依曼体系结构,对机器指令的抽象,但是其命令式的特征最根本的来源其实还是图灵机,因为现行计算机的硬件结构(冯诺依曼体系结构)就是图灵机的直观实现,就连冯诺依曼本人也曾说过(当然有可能是谦虚的说法):存储程序思想不是自己最先提出来的,除掉巴贝奇等人的工作,这个思想基本上可以说是属于图灵的。因此无论冯诺依曼体系结构也好,图灵机也好其实都是命令式,基于状态转换的,从这点上看计算机的机器本质和数学本质其实是统一的。
参考文献:程序设计语言-实践之路 Michael Scott
程序设计原理 8th edition Robert W. Sebesta