现在的位置: 首页 > 综合 > 正文

Programming Paradigms 编程范式-笔记

2013年10月17日 ⁄ 综合 ⁄ 共 2963字 ⁄ 字号 评论关闭

Stephen Covey的《The 7 Habits of Highly Effective People》一书中,有一个关于paradigm shift(范式转移)的小故事:
军舰在雾天执行紧急任务,突然发现船的一侧有来自其他处的照明灯光,舰长要求对方转向,否则有两船相撞的危险。可惜对方坚持让军舰转向,互不相让。舰长甚至亮出了自己的军衔相挟“我是海军上校,这里是军舰!”。而最后的结果,却是本来态度强硬的军舰选择了转向,因为对方的答复是:“我是二等兵,这里是灯塔!”
虽然关于范式的准确定义,说法有很多,我也不打算深究并记录进笔记,但从这个小故事中可见,范式是我们思考的一种模式,正确的模式会让我们更加接近真实,更容易达到特定的目的,而错误的模式则会让我们事倍功半。
我们学习编程都是从具体的编程语言,如C,C++,java等开始的。所以一开始往往没有深入接触programming paradigms(编程范式)的概念,最多是简单地介绍一句“C是面向对象的编程语言“,再多问一句,得到的回答也只是”以后你学到C++就会发现它是面向对象的编程语言“。其实这里面有很多深刻的话题可以谈论,值得深入地考虑。譬如说,一门语言和编程范式的关系,并非是”C是面向对象的编程语言“的关系那么简单,一门编程语言和编程范式其实没有绑定或者专属的关系,一个是语法语义层面的,另外一个是运算算法层面的,一般说某种编程语言支持某种编程范式可能比较恰当,甚至有一些语言还支持混合编程范式。其实C也能支持一些面向对象的因素,只是不如其他按照OOP(Object-oriented
Programming)范式开发的语言支持得完善(继承、多态、重载?),所以说”C是面向对象的编程语言“也能让人接受,而C++也能做到纯粹的面向过程,但作为C的超集,其最大的不同就是对OOP的支持,故把它称为面向对象的编程语言。

编程范式的分类也有很多种,除了上面的分类,还有结构化、非结构化等分类。我想最主要的分类还是按照model of computation(计算模型)来分,一般而言有四类范式:

  • 基于Turing Machine(图灵机)的Imperative Programming(命令编程范式);
  • 基于Turing Machine(图灵机)的Object-oriented Programming(面向对象的编程范式);
  • 基于λ-calculus(λ演算)的Functional Programming(函数编程范式);
  • 基于First-order logic(一阶逻辑)的Logic Programming(逻辑编程范式)。

关于编程范式的分类也十分复杂,想深究的可以留意下图:

命令式编程范式主要是”发号施令“形式的编程模式,程序按照一定的顺序执行各条指令,程序员需要具体到程序如何去做的层次。而与之相对的是Declarative Programming(声明编程范式),只须程序员指明做什么的层次,而无需深入具体如何做的层次,函数编程范式和逻辑编程范式均是声明编程范式,下文再加以介绍。这种”发号施令“式的编程范式贴合硬件的执行,是最早的编程范式,一环接一环,环环相扣地执行,所以任何一个细节出错可能都会导致整个程序的错误。为了满足Low coupling(低耦合), High cohesion(高内聚)的设计模式,面向过程式的编程范式(也是命令式编程范式一种)渐渐发展起来,其最大特色就是把所有程序分化为逐个子函数或者子程序(C里面几乎所有有执行意义的代码都需要在某个函数里,如main函数等)。而且它引入的变量、函数返回值等机制,使整个程序高度模块化,把状态的改变对应到不同的子函数之中去。因而也有很强的Side
Effect。这种编程范式和图灵机的设想很贴合,也是编程方面比较主流的范式(软硬件条件共同决定的)。

随之而来发展出了面向对象的编程范式,如果某种语言支持这种范式,意味着支持继承、多态、抽象、封装、重载等等功能。从面向过程式的编程范式到面向对象式的编程,编程范式有了一个新的提高,因为面向对象的编程范式提出了类、对象、实例等概念,一方面贴合我们的思维,另外一方面也为代码的重复利用做了很大贡献。相比于命令式编程,其模块化更为淋漓尽致,子函数的角色被模糊融合到各个类、对象中去,且各个类、对象又有独自的数据和方法,能够相互收发信息,这样写出来的程序不如传统的命令编程范式般冗长,简洁明了。但从实际上来说依然是图灵机的模型。

以上两种编程范式应该最为程序员所熟悉,占据了大半壁江山。

函数编程范式则摒弃了看重数据和状态的计算模型,也就摒弃了副作用。找眼于函数本身,而非执行的过程的数据和状态的处理。Haskell是其代表语言之一。函数编程范式在商业上应用不如在研究领域的应用广泛和突出。爱大曾在70年代发明了ML函数式编程语言,也在这个领域有不少的贡献,至今Functional Programming都还是信息学院的大一必修课,让很多新生头疼。下面看一个斐波那契数列的例子:


C++:

#include <iostream>
// Fibonacci numbers, imperative style
int fibonacci(int iterations)
{
int first
=
0, second
=
1;// seed values
for
(
int i
=
0; i< iterations-1;++i){
int sum
=
first + second;
first = second;
second = sum;
}
return first;
}
int main()
{
std::cout<< fibonacci(10)<<"\n";
return
0
;
}

Haskell:

fibonacci2
=
0:1:zipwith(+)
fibonacci2(tail fibonacci2)

就那么简明,是不是有耳目一新的感觉呢?

就那么简明,是不是有耳目一新的感觉呢?
逻辑编程范式和函数编程范式相类似,但也不同,它所确立的简单规则就是:事实+规则=结果。这种按照逻辑规律去产生结果的范式,更大程度地把程序从对数据的处理中解放出来。是一个从更抽象层次考虑问题的范式。代表语言是Prolog,爱大是Prolog的发源地。逻辑编程范式被普遍运用于人工智能领域。可以看一下面一段简单例子:



father_child(tom, sally).
father_child(tom, erica).
?-sibling(sally,erica).


若sally的父亲是tom,erica的父亲是tom,那么sally和erica是兄弟姐妹关系么?答案是Yes。

总之不同的编程范式在算法设计、编程风格上都有很大的不同,它们各有特点,也各自运用于不同的领域,对它们的研究会随着软硬件的发展而持续下去。

     
     
一些相关的参考资料:
   
维基百科(参考了部分代码)

Programming Paradigms for Dummies: What Every Programmer Should Know (Peter Von Roy,Université catholique de Louvain à Louvain-la-Neuve,本文分类图来源 )

Programming paradigms(Jerry Cain,Standford University)

抱歉!评论已关闭.