1.0 Building Abstractions with Procedures - CloneableX/SICP-learning GitHub Wiki
思维之所以能够处理复杂问题,主要是因为下列三点:
- 它能够将几个简单的概念结合起来,所有复杂的概念都是如此生成的
- 它能够将两个概念(无论是简单的还是复杂的)置于同一视角比对,并因此获取它们相关的所有概念
- 它可以将概念从实践中分离(这就是抽象能力),所有的通用概念都由此而来 —— John Locke, An Essay Concerning Human Understanding (1690)
我们将要学习 计算过程(computational process) 的相关概念。计算过程是计算机行为的抽象。随着科技发展,计算过程能够维护一些事物,这些事物被称为 数据(data)。
计算过程由一种被称为 程序(program) 的规则模式操纵。人们通过程序操作计算过程。其实,这相当于我们通过咒语唤醒了计算机的灵魂。
计算过程与巫师口中的灵魂概念十分相似,虽然它无法被看见也无法被感知,但却如此真实。计算过程既能执行智能化的任务,也能回答问题,它能通过生活的方方面面影响世界。程序恰恰像是巫师的咒语,通过将玄妙的符号和深奥的 编程语言(programming languages) 结合能够制定需要计算过程处理的任务。
计算过程可以在正常的电脑中精确地执行程序。就像巫师一样,程序员也需要学习理解和预测咒语生产后的结果,因为程序中即使是一个极小的错误(通常被称为 bugs 或 glitches)也可能引起混乱和无法预料的后果。
所幸学习编程并不像学习咒语那样危险,因为我们处理的灵魂以一种便携、安全的方式存放着。不过现实世界的编程工作同样需要细心、专业知识和智慧。毕竟一个程序设计时的小问题可能引起巨大的灾难,例如飞机、堤坝或工业机器人的自毁。
熟练的软件工程师都拥有有效组织程序,并能合理推测出程序运行结果的能力,他们可以想象出系统运行时的行为。同样,他们也知道应该如何架构程序,保证程序出现问题时不会导致巨大的灾难。当问题浮现时,他们便能排查出其中的问题。良好设计的计算系统,就如同设计良好的汽车或核反应堆,它们都采用模块化的方式构建,这种方式导致它们可以被部分隔离地构造、替换和排查问题。
使用 Lisp 编程
我们需要一门合适的语言描述计算过程,Lisp 完全符合我们的需要。如同我们的思维通过自然语言进行表达,定量现象通过数学符号表达一样,计算过程通过 Lisp 表达。 Lisp 在 20 世纪 50 年代被发明,随后被作为某些逻辑表达式的表现形式存在,这种计算模型也被称为 递归方程(recursion equations)。Lisp 从 John McCarthy 的构想中诞生,这份构想来自他的论文《Re-cursive Functions of Symbolic Expressions and Their Computation by Machine》。
尽管 Lisp 的创建之初只是作为数学表现形式存在,但同时它也是一门实用的编程语言。Lisp 解释器负责执行 Lisp 表达的计算过程。世界上第一个 Lisp 解释器由 McCarthy 在 MIT 电子研究室和计算中心的人工智能组成员帮助下完成。Lisp 实际是 LISt Processing 的首字母缩写,它拥有多符号操作的能力,能够解决类似微积分的编程问题。除此之外,它还为了创建被称为 atom 和 list 的数据对象而生,这个能力使其比过去的编程语言更加吸引眼球。
Lisp 并不是一款协同设计的产物,它的演进是非正式的,它是一场根据用户需求反馈的实验,接着将这些想法进行了实现。Lisp 的这种演进持续了许多年,同时 Lisp 社区的用户保持着反对向外部宣布 Lisp 官方定义的传统。这种思想使 Lisp 能够持续适应不断更新的程序设计理念,所以 Lisp 也产生了许多方言,它们既拥有一些 Lisp 共同的特性,也发展出不同的新特性。本书中使用的 Lisp 方言是 Scheme。
因为它既是实验性语言,又将重心放在符号维护上,所以早期的 Lisp 在数字计算上的效率不如 Fortran。不过经过多年的努力,Lisp 编译器已经能够将程序转换为机器编码,这极大提升了 Lisp 在数字计算上的效率。而且在某些应用的开发上,Lisp 也有高效的表现。尽管这并没有为 Lisp 挽回效率低下的不良名声,但它依然被很多未将效率作为第一要务的应用采用。例如,Lisp 已经成为 shell 脚本的语言,还有一些编辑器和电脑辅助设计系统的扩展语言。
既然 Lisp 不是主流语言,为什么我们还是选择它作为讨论程序课题的框架?因为 Lisp 拥有独特的特性,这个特性使它成为学习编辑构造、数据结构及相关语言学支持的优良媒介。Lisp 中的重要特性 程式(procedures) 作为 Lisp 的数据被维护和表达。这是一种十分重要的程序设计技术,依靠这种能力才能使静态的数据和动态的方法间的差别被弥合。基于这些发现,Lisp 将程式作为数据处理的灵活特性使它成为探索这些技术时最方便的语言。这种能力也使 Lisp 可以写出将其他程序作为数据维护的程序,比如支撑电脑语言的解释器和编译器。基于这些考虑,Lisp 十分契合本书的课题。