构造过程抽象
心智的活动,除了尽力产生各种简单的认识之外,主要表现在如下三个方面:
- 将若干简单的认识组合为一个复合认识,由此产生出各种复杂的认识。
- 将两个认识放在一起对照,不管它们如何简单或者复杂,在这样做时并不将它们合而为一。由此得到有关它们互相关系的认识。
- 将有关认识与那些在实际中和它们同在的所有其他认识隔离开,这就是抽象,所有具有普遍性的认识都是这样得到的。
————John Locke, An Essay Concerning Human Understanding
1. 程序设计的基本元素
一种强有力的程序设计语言,不仅是一种指挥计算机执行任务的方式,它还应该成为一种框架,使我们能够在其中组织自己有关计算过程的思想。每一种强有力的语言都为此提供了三种机制:
- 基本表达形式————用于表示语言所关心的最简单的个体
- 组合的方法—————通过它们可以从较简单的东西出发构造出复合的元素
- 抽象的方法—————通过它们可以为复合对象命名,并将它们当作单元去操作
在程序设计中,我们需要处理两类要素:过程和数据。非形式的说,数据是一种我们希望去操作的“东西”,而过程就是有关操作这些数据的规则的描述。这样,任何强有力的程序设计语言都必须能表述基本的数据和基本的过程,还需要提供对过程和数据进行组合和抽象的方法。
1.1 表达式
1.2 命名和环境
1.3 组合式的求值
处理组合式的求值,按照如下的方式进行处理:
- 数的值就是它们所表达的数值。
- 内部运算符的值就是能完成相应操作的机器指令序列。
- 其他名字的值就是在环境中关联于这一名字的那个对象。
环境所扮演的角色就是用于确定表达式中各个符号的意义。
1.4 复合过程
Lisp 提供的一些基本元素,包括:
- 数和算术运算是基本的数据和过程。
- 组合式的嵌套提供了一种组合起多个操作的方法。
- 定义是一种受限的抽象手段,它为名字关联相应的值
过程定义是一种威力更加强大的抽下技术,通过它可以为复合操作提供名字,而后就可以将这样的操作作为一个单元使用了。
![]()
1.5 过程应用的代换模型
有两种形式:
- 正则序———完全展开而后归约。
- 应用序———先求值参数而后应用(Lisp),可以避免重复求值。
编写程序(课后习题 1.5)来验证解释器是哪一种。
然后求值下面表达式,即可知道。
- (test 0 (p))
解释:首先 (define (p) (p)) 定义了一个死循环,直接调用 (p) 进入死循环。
- 如果是正则序,首先替换 (test x y) 中的 x,y,得到 (test 0 (p))。因此替换后得到:(if (= 0 0) 0 (p)),于是跳过了死循环。
- 如果是应用序,首先计算 (test x y) 的每个参数,计算 y ( (p) ) 时,就进去死循环了。
在 guile 的测试中,程序进入了死循环,说明是应用序求值的。
1.6 条件表达式和谓词
关键词 cond、and、or、not 的使用。
1.7 实例:采用牛顿法求平方根
1.8 过程作为黑箱抽象
对于平方根的计算问题,可以自然的分解为若干子问题:一个解怎样算作足够好?怎样去改进一个解等等。这些工作中的每一个都通过一个独立的过程完成,整个 my-sqrt 程序可以看作一族过程,它们直接反应了从原问题到子问题的分解。过程的分解如下图所示:
内部定义和块结构。 如下程序中嵌套的定义称为
块结构。如下程序中,在外围的 my-sqrt1 被调用时,x 由实际参数得到自己的值,这种方式称为
词法作用域。
参考: