浅析函数式编程与命令式编程的区别(二)设计的区别

  命令式语言之间的高度类似的部分来自于他们共同的设计基础之一:冯诺依曼体系结构。我们可以整体地将命令式语言视为在Fortran 的基本模式上的发展。所有的命令式语言都被设计来高效地使用冯诺依曼体系结构的计算机。实际上,最初的命令式语言的目的就是取代汇编语言,对机器指令进行进一步抽象。因此,命令式语言带有强烈的硬件结构特征。命令式语言的核心特性有:模拟存储单元的变量、基于传输操作的赋值语句,以及迭代形式的循环运算。命令式语言的基础是语句(特别是赋值),它们通过修改存储器的值而产生副作用(side effect)的方式去影响后续的计算。

  函数式语言设计的基础是数学函数,函数式程序设计把程序的输出定义为其输入的一个数学函数,在这里没有内部状态,也没有副作用。函数式语言进行计算的主要是将函数作用与给定参数之上。函数式语言没有命令式语言所必需的那种变量,可以没有赋值语句,也可以没有循环。一个程序就是函数定义和函数应用的说明;一个程序的执行就是对函数应用的求值。

  在继续进行讨论之前,这里先对两个概念进行介绍。一个是对命令式语言至关重要的副作用(side effect),另一个就是对函数式语言设计基础的数学函数。

  我们先来看看维基百科对副作用的解释:

  In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world. 

  翻译过来就是:在计算机科学中,一个函数或表达式,如果除了返回值之外,还修改了某个状态或者和调用它的函数或外部环境进行了明显地交互,就被称为是有副作用的。

  命令式语言就是通过副作用来改变机器状态,与外部环境进行交互的,从而执行整个计算过程的。命令式语言里的表达式或函数不仅有求值的功能,还有进行状态转换的功能。

       数学函数就是一个集合到另一个集合的映射,前一个集合被称作定义域集,后一个集合被称作值域集。一个函数定义就是显式或隐式地说明定义域到值域的映射。数学函数的基本特性之一,是由递归和条件表达式所控制的、它们的映射表达式的求值次序,而不是命令式语言中常用的顺序以及循环的重复。数学函数另外的一个重要特性是,当给定一组相同的自变量是,他们总定义相同的值。数学上没有任何东西可以模拟存储单元,命令式语言函数中的局部变量保存函数的状态,而数学上,没有函数状态这一概念。一个数学函数就定义一个值,而不是说明从内存的值生产另一个值的运算序列。

       最后举个列子来说明这个不同:(还是上一篇的求最大公约数)

Pascal编写的一个命令式程序:

function gcd(m,n: integer):integer;

var tmp:integer;

begin

       while m<>0 do

       begin

              tmp:=m;

              m:=n mod m;

              n:=tmp;

       gcd:=n

       end;

这个函数实际上就是一个指令序列通过改变内存的三个单元控制程序流程来实现欧几里德算法。

再看看用ML语言写的函数式程序:

fun gcd (m,n)=

       If m=0 then n

              else gcd (n mod m,m);

是不是感觉跟定一个数学上分段函数很像,只不过这里用的是if-then-else。

 

作者曰:函数式语言是跟打交道的,基础是表达式,命令式语言是跟状态打交道的,基础是语句。这就是两者设计上的根本不同,命令式程序可以看成一个指令序列,通过改变存储单元的值来改变机器状态来实现算法。而函数式语言可以看成一个由输入到输出的函数,而这个函数又由其他函数或者自身来构造。实现算法的过程就是由语言提供的原始函数逐步构造一个符合算法要求的函数的过程。

 

参考文献:程序设计语言-实践之路  Michael Scott

     程序设计原理 8th edition Robert W. Sebesta

     ML程序设计教程 Lawrence C. Paulson

posted on 2011-11-22 16:37  lisperl  阅读(4513)  评论(16编辑  收藏