基本范式
人生最伟大的目标是行动 ——《洛克菲勒的忠告》
第二课伊始,冒号开门见山:“首先介绍的是最基本的两种编程范式:命令式和声明式,其中命令式又称过程式。通俗点说,命令式编程由命令序列组成,即一系列祈使句:‘先做这,再做那’,强调‘怎么做’;声明式编程由相关表达式组成,即一系列陈述句:‘已知这,求解那’,强调‘做什么’。学术点说,命令式编程是电脑(von Neumann机)运行机制的抽象,即有序地从内存中获取指令和数据然后去执行;声明式编程是人脑思维方式的抽象,即利用数理逻辑或既定规范(specification)对已知条件进行推理运算。”
引号嘟囔着:“大多数语言好像都是命令式的。”
冒号接口道:“语言的演化是渐进的,大多数语言追根溯源是汇编语言的升级,而作为与机器语言一一对应的汇编语言自然是命令式的,因而这种范式最为传统和普及。声明式语言则发轫于人工智能的研究,主要包括函数式语言和逻辑式语言。其实它们的出现并不比命令式的晚多少——最早的函数式语言Lisp(LISt Processor)已有半个世纪的历史,最早之一的逻辑式语言Prolog(PROgramming in LOGic)也与C同龄。只是由于大多数更多地用于学术研究而非商业应用,颇有些‘养在深闺人未识’。起源的不同决定了这两大类范式代表着迥然不同的编程理念和风格:命令式编程是行动导向(Action-Oriented)的,因而算法是显性而目标是隐性的;声明式编程是目标驱动(Goal-Driven)的,因而目标是显性而算法是隐性的。为便于说明,下面分别用三种代表性的语言来实现阶乘(factorial)运算。”
冒号在黑板上打出投影——
C(命令式):
int factorial(int n)
{
int f = 1;
for (; n > 0; --n) f *= n;
return f;
}
Lisp(函数式):
(defun factorial(n)
(if (= n 0) 1 // 若n等于0,则n!等于 1
(* n (factorial(- n 1))))) // 否则n!等于n* (n-1)
Prolog(逻辑式):
// 0! 等于1
factorial(0,1).
// 若M等于N-1且 M!等于Fm且F等于N*Fm,则N! 等于F
factorial(N,F) :- M is N-1, factorial(M,Fm), F is N * Fm.
冒号提问:“撇开语法细节,大家说说以上三段代码区别在哪里?”
句号沉思片刻,答道:“C明确给出了阶乘的迭代算法,而Lisp仅描述了阶乘的递归定义,Prolog则陈述了两个关于阶乘的断言。”
冒号很满意:“一语中的!第二个问题:你们更习惯哪一种思维方式?”
逗号不加思索:“当然是第一种!”
冒号微笑着说:“这证明你至少是受过一定训练的程序员。大家回想一下,当你们初学编程时,是否习惯这种思维方式?”
叹号沉吟道:“好像不太习惯i = i + 1之类的语句。”