
译作:计算机编程的结构与解释
从编译原理的角度理解计算机的编程,以达到编程的可扩展性,可维护性,可重用性等
王伟1982
我是数据分析与处理行业的数据采矿工,软件业的代码搬运工,通信业的协议打包工,互联网业的安全检查工
展开
-
翻译连载: 第0篇 计算机编程的结构与解释 译者的序言
计算机编程的结构与解释,这是一本美国的大学教材。几年前我就译了一部分,今年又接着译下来。计算机的理论与实践的结合十分紧密的学科。国内的教材,像参考书,或者是某某使用指南似的,罗列了知识点。如果会了这种知识,去查找相关的知识,是有益的。如果让学生入门,是不容易的。计算机编程的结构与解释以实践为主线,在其中穿插了算法分析,数据结构,编译原理,汇编语言,门电路逻辑等相关的编程理论内容。让我们能够了解...原创 2018-06-08 14:42:23 · 228 阅读 · 0 评论 -
翻译连载: 第1篇 计算机编程的结构与解释 目录
目录序言第二版的前言第一版的前言致谢引用练习题的列表索引1. 用程序构建抽象 1.1编程的元素 1.1.1 表达式 1.1.2 命名与环境 1.1.3 评估组合子 1.1.4 组合性的程序 1.1.5 对于程序性的应用的替代模型 1.1.6 条件表达式和条件语句 1.1.7 例子:牛顿法求平方根 1.1.8 作为黑盒抽象的程序 1.2程序和它们生成的流程 ...翻译 2018-06-08 14:46:48 · 217 阅读 · 0 评论 -
1.2.5 最大公约数
1.2.5 最大公约数两个整数A和B的最大公约数是能够被A和B整除的最大整数.例如16和28的最大公约数是4,在第二章中,我们考察如何实现有理数的算术,我们将需要能够计算最大公约数,为了分数的简化操作.(为了把一个分数简化到最简化的形式,我们必须用分子与分母除以它们的最大公约数 例如 16/28 简化为 4/7).求最大公约数的方法是求它们的因数,再找共同的部分,然而有一个著名的算法...翻译 2018-08-04 16:13:40 · 519 阅读 · 0 评论 -
1.2.6 例子:素数的测试
1.2.6 例子:素数的测试这一部分描述检测一个整数的素数性的两种方法。一个的成长序是平方根N,一个快速的方法是log(n).这部分结尾的练习建议编程项目基于这些算法。* 检索除数因子从古代,数学家们已经痴迷于素数的问题。许多人研究测试一个数是不是素数的方法的问题。测试一个数是不是素数的方式之一是找它的除数因子。如下的程序找一个给定的整数的大于1的最小的整数的除数因子。它以一种很自...翻译 2018-08-04 16:15:15 · 510 阅读 · 0 评论 -
1.3 用高层次的函数对抽象进行公式化
1.3 用高层次的函数对抽象进行公式化我们已经看到的程序,在效应上,抽象是指独立于数据的对数据的组合性的操作。例如当我们写 (define (cube x) (* x x x))我们不是指一个特定的数的立方,而是关于任何一个数的立方。当然了如果我们不定义这个立方的程序,而是总是写如下的表达式 (* 3 3 3 )(* x x x )(* y y y )并且根本没有显式的提到 ...翻译 2018-08-04 16:16:44 · 169 阅读 · 0 评论 -
1.3.4 程序作为返回值
1.3.4 程序作为返回值以上的例子都显示了把程序作为参数的能力是如何极大地增强了我们的语言的表现能力。通过创建返回值也是程序本身的程序,我们能够得到更大的表现能力。通过回顾一下1.3.3部分结尾的不动点例子,我们能显示这种思想。以不动点的搜索方式,我们写了平方根程序的新版本,开始注意到x的平方根,是函数 Y=x/y的一个不动点。然后,我们使用平均技术使得结果收敛。平均技术是一种很有...翻译 2018-08-04 16:24:05 · 334 阅读 · 0 评论 -
2.5.3 例子:符号化的代数
2.5.3 例子:符号化的代数符号代数表达式的操作是一个复杂的执行过程,它演示出诸多发生在大型系统的设计中的最难的问题。一个代数的表达式,总之,能被表示为一个层次化的结构,是把操作符应用到操作数上的树。我们能组装代数表达式以原生的对象的集合开始,例如常数和变量,组合它们,使用代数符号,例如加法,乘法。像其它语言一样,我们能形成抽象,让我们有能力,以简单的术语引用复杂的对象。在符号代数中的...翻译 2018-08-09 08:26:55 · 543 阅读 · 0 评论 -
3. 模块化,对象和状态
3. 模块化,对象和状态即使它变了,但它还在。前面的章节介绍了编程需要的基本元素。我们看到了原生的程序和原生的数据是如何组装成复合的实体的,并且我们学到了在帮助我们对付大系统的复杂性方面抽象是极为重要的。但是这些工具对于设计程序是不够的。高效的程序这种人工产物也需要有组织原则来指导我们对编程设计的全过程进行规范化。尤其是我们需要帮助我们对大系统进行结构化的策略,为了这种系统将被模块...翻译 2018-08-09 08:28:46 · 330 阅读 · 0 评论 -
2. 用数据构建抽象
我们现在来到了数学抽象的关键步骤:我们忘记符号代表什么,数学家们不需要空闲,用这些符号他能执行许多的操作,没有不得不让这些符号代表什么。---思考的数学方式 我们在第一章中着重研究了计算流程和程序设计中的子程序的角色。我们已经看到了如何使用原生的数据,原生的操作符,通过使用组合条件,形式参数等如何组合子程序来形成复杂的程序,和使用定义的方法来如何抽象程序。我们看到了一个程序能够...翻译 2018-08-05 08:56:23 · 265 阅读 · 0 评论 -
2.1数据抽象的介绍
在1.1.8部分中,我们注意到在创建一个复杂的程序时,一个程序能作为其中的一个元素使用,这被认为不仅作为一个特定的操作的集合,而是一个程序性的抽象。也就是说,如何实现程序的细节能够被隐藏起来,特定的程序的本身也能被有相同的行为的其它程序替换掉。换句话说,我们能制造出一种抽象,以更原生的程序为工具,把程序的使用方式同程序如何实现的细节分离开。对于复合的数据,相似的观念叫做数据抽象。数据抽象...翻译 2018-08-05 08:57:43 · 275 阅读 · 0 评论 -
2.1.1 例子:有理数的算术操作
2.1.1 例子:有理数的算术操作假定我们要实现有理数的算术。我们要能够做加法,减法,乘法,和除法,以及测试两个数是否相等。让我们开始假定我们已经有一种方式从分子和分母组装起一个有理数。我们也假定给定一个有理数,我们有一种方式抽取出它的分子和分母。让我们进一步地假定组合子和选择子都是可用的,如下的程序:(make-rat <n> <d>) 返回一个有理数,它...翻译 2018-08-05 08:58:39 · 558 阅读 · 0 评论 -
2.1.2 抽象隔离
2.1.2 抽象隔离在继续关于复合数据和数据抽象的更多的例子之前,让我们考虑一些由有理数例子产生的一些问题。我们定义了有理数的操作,是用make-rat和numer,denom.总之,数据抽象的根本思想是为每种数据对象标识出一个基本的操作集合。这个集合能把那种类型的数据对象的所有的操作都表达出来,然后仅使用那些已定义的操作来操作数据。 我们能够重审视一下有理数系统的结构。见图2。...翻译 2018-08-05 08:59:45 · 212 阅读 · 0 评论 -
2.1.3 数据意味着什么
2.1.3 数据意味着什么我们开始有理数的实现,在2.1.1部分,通过使用三个未特定的程序make-rat,numer,denom,实现了add-rat,sub-rat等等.在那一点上,我们认为操作被定义在数据对象分子,分母和有理数。它们的行为被这三个程序指定。但是数据的准确的含义是什么呢? 说能被指定的选择子和组装子实现的东西是不充分的。这三个程序的集合是清楚的,不是随意的。这个集...翻译 2018-08-05 09:00:37 · 294 阅读 · 0 评论 -
2.1.4 扩展训练: 区间算术
2.1.4 扩展训练: 区间算术"Alyssa P. Hacker" 正设计一个系统来帮助人们解决工程问题.在她的系统中她要提供的特征是操作的量有确定的精度(例如物理设备的测量参数)的能力.当计算执行的时候,这个结果量也有确定的精度.电气工程师们使用"Alyssa"系统计算电气的量.对于他们而言,计算两个电阻R1和R2的并联电阻的等价值Rp的值是必须的。使用如下的公式:Rp=1/(...翻译 2018-08-05 09:01:40 · 519 阅读 · 0 评论 -
3.1赋值语句与当前的状态
3.1赋值语句与当前的状态我们通常把世界看作是由独立的对象(个体)组成的,任何一个个体都有一个随时间而改变的状态。如果一个个体的行为受到它的历史的影响,那么我们可以说这个个体是有状态性的。例如一个银行账户是有状态的,这个状态存在于 “我能取100元吗”这个问题的答案中。这个答案依赖于存款与取款的事务的历史情况。我们能够用一个或者是多个状态变量来特征化一个对象的状态,这些状态变量中维护...翻译 2018-08-09 18:54:21 · 119 阅读 · 0 评论 -
3.1.1 当前状态的变量
3.1.1 当前状态的变量为了演示有一个时变状态的计算对象的含义,让我们对从一个银行账户取款的情况来做模型。我们用一个程序withdraw 实现这个操作,这个程序需要一个取款金额的实际参数。如果账户中的金额比取款金额大,那么取款程序将返回取款后的余额。否则,程序返回余额不足的消息。例如,如果我们开始操作时,账户中有余额100元,我们在取款中将得到如下的返回序列。(withdraw 25...翻译 2018-08-09 18:56:24 · 323 阅读 · 0 评论 -
2.2层次化数据与闭包属性
2.2层次化数据与闭包属性正如我们已经看到的,数据对提供一个原生的让我们能够组装复合数据对象的胶水。图2.2中,显示了一个可视化数据对的标准方式,在这个例子中,由 (cons 1 2)形成了一个数据对。在这个表示法中,它被叫做黑盒与指针法,像任何一个对象都被表示成一个指针指向一个黑盒。 对于一个原生的对象这个黑盒就是这个对象的表示。例如,一个数字的黑盒表示一个数字。一个数据对的黑盒...翻译 2018-08-05 20:51:26 · 199 阅读 · 0 评论 -
2.2.1 表示序列
2.2.1 表示序列我们用数据对构建的有用的结构之一是序列。即数据对象的有序的集合。当然了,用数据对有多种方式表示序列。一个特别的常规的表示方式如图2.4序列1,2,3,4被表示为一个数据对的链。 任何一个数据对的头部相对应的是链中的一个项,数据对的尾部是链中的下一个数据对。 最后一个数据对的尾部通过指向一个数据对中不存在的特殊值,来标识着序列的结尾处,这个特殊的值,在黑盒与指针图的...翻译 2018-08-05 20:53:01 · 594 阅读 · 0 评论 -
3.1.2 介绍赋值语句的好处
3.1.2 介绍赋值语句的好处正如我们看到的,把赋值语句引入我们的编程语言,让我们有一把应对有难度的概念问题的钥匙.无论如何,把系统看成是有当前状态的一群对象的集合是为了维护一个模块化的设计的强有力的技术.正如一个简单的例子,考虑一下 随机数程序的设计,无论何时被调用,都能返回一个随机数.“近似的随机”意味着什么,是根本就不清楚的。假设我们所要的是对于随机程序的连续的调用,生成了...翻译 2018-08-10 08:01:48 · 438 阅读 · 0 评论 -
3.1.3 介绍赋值语句的代价
3.1.3 介绍赋值语句的代价正如我们已经看到的,set!操作让我们对有局部变量的对象进行了模型化。然而,这种优势带来了代价。我们的编程语言不再能以替换模型进行解释了。进而,在编程语言中,对于处理对象和赋值而言,没有具有很好的数学属性的简单的模型能成为一个足够好的框架。只要我们不使用赋值,相同的程序有相同的参数的两次解释将生成相同的结果,因此程序能被视为一个数学函数。没有使用任何赋...翻译 2018-08-10 08:05:04 · 224 阅读 · 0 评论 -
2.2.2 层次结构
2.2.2 层次结构序列的表示是用列表的方式,序列的元素本身也能是序列。例如,我们能够把对象((1 2) 3 4) 以如下的方式组装起来。(cons (list 1 2) (list 3 4))作为有三个元素的列表,第一个元素是一个列表(1,2).的确,用解释器打印出结果,是有建设性的。图2。5是以数对的形式表示了这个结构。 ...翻译 2018-08-06 08:09:22 · 197 阅读 · 0 评论 -
2.2.3 序列作为一致化的接口
2.2.3 序列作为一致化的接口在使用复合数据的时候,我们有点紧张,数据抽象是如何让我们能够设计程序却没有被数据表示的细节所困扰,数据抽象是如何让我们保留了 试验多种表示方式的灵活性。在这部分中,我们要介绍另一种强有力的设计原则,这种原则针对的是数据结构的使用。设计原则是使用一致化的接口在1.3部分中,我们看到了程序如何抽象,实现为一个高层次的程序,能够捕捉到处理数字的程序的共同模式...翻译 2018-08-06 08:10:36 · 212 阅读 · 0 评论 -
2.2.4 例子:一个图片的语言
2.2.4 例子:一个图片的语言这部分表示了一个简单的语言,这个语言用来画图。它演示了数据抽象和闭包的威力,也以一个必要的方式,显式地显示出高阶程序。语言被设计成,使它容易实验,结合图2.9中的这样的模式。这模式是重复的图片的组合。这个图片可以拉伸与缩放。在这种语言中,数据对象能被组合,能被表示为程序而不是列表结构。正如cons,它能满足闭包属性,允许我们很容易地随意的构建复杂的列表结...翻译 2018-08-06 08:12:38 · 462 阅读 · 0 评论 -
3.2评估的环境模型
3.2评估的环境模型当我们在第一章介绍复合程序时,在1.1.5部分中,我们使用评估的替换模型来定义出把程序应用到参数上的含义。为了应用一个复合程序到参数上,要评估程序体,并且把形式参数替换成对应的实际参数。一旦我们把赋值语句加入到我们的语言中,这样的定义就不充足了。特别是在3.1.3部分中的讨论那样,有赋值语句的存在,一个变量不再被认为仅是一个值的名称了。而是一个变量必须要在某种程度上...翻译 2018-08-10 22:13:12 · 1088 阅读 · 0 评论 -
3.2.1 评估的规则
3.2.1 评估的规则解释器如何评估一个组合的表达式的整体性的规范,与我们在1.1.3部分中开始介绍的内容是一致的。为了评估表达式:1。评估表达式的子表达式2。应用操作符子表达式的值到操作数子表达式的值。评估的环境模型,代替了替换模型,用来指定,应用一个复合程序到参数的含义。在评估的环境模型中,一个程序总是一个数对,包括了一些代码和一个指向环境的指针。程序被创建仅有一种方式。即通...翻译 2018-08-10 22:19:47 · 296 阅读 · 0 评论 -
2.3符号化的数据
2.3符号化的数据我们所使用的所有的复合的数据对象最终都是由数字组成的。在这一部分中,我们通过引入符号数据的能力来扩展我们的语言的表现力。 2.3.1 引用如果我们能用符号来形成复合的数据,我们能有如下的列表(a b c d)(23 45 17)((Norah 12) (Molly 9) (Lauren 6) (Charlotte 4))能够包含符号的列表看起来...翻译 2018-08-06 17:59:56 · 920 阅读 · 0 评论 -
2.3.2 例子:符号化的微分
2.3.2 例子:符号化的微分作为一个符号操纵的演示例子,和一个数据抽象的深入一步的例子,考虑一下代数表达式的符号微分的执行的程序的设计。我们要这个程序输入一个代数表达式和一个变量,返回这个表达式对这个变量的微分结果。例如 程序的输入参数是 ax2+bx+c 和x ,结果是 2ax+b。在LISP中,符号微分具有特殊的历史意义。它是为符号运算设计的计算机语言的开发背后,有动机的例子之...翻译 2018-08-06 18:03:29 · 418 阅读 · 0 评论 -
3.2.2 应用简单的程序
3.2.2 应用简单的程序当我们介绍1.1.5部分中的替换模型时,我们显示了如何把组合表达式(f 5)解释成136,给出了如下的程序定义:(define (square x) (* x x)(define (sum-of-squares x y) (+ (square x) (square y)))(define (f a) (sum-of-squares...翻译 2018-08-11 10:14:21 · 278 阅读 · 0 评论 -
3.2.3 帧作为当前状态的仓库
3.2.3 帧作为当前状态的仓库我们能返回环境模型,来看看程序和赋值如何能被用来表示有局部状态的对象。作为一个例子,考虑3.1.1部分中创建的取款例子。由如下的程序:(define (make-withdraw balance) (lambda (amount) (if (>= balance amount) (begin (set! b...翻译 2018-08-11 10:16:48 · 218 阅读 · 0 评论 -
3.4并发:时间是本质
3.4并发:时间是本质作为建模的工具,我们已经看到了有局部状态的计算对象的威力。然而,正如在3.1.3部分中的警告那样,这种威力抽取一种价值,引用透明性的损失,提高关于相同性与修改的问题的门槛,需要放弃评估的替换模型,取而代之的是更难于理解的环境模型。核心的问题悄悄地潜藏于 状态,相同性和修改的复杂性之下。通过介绍赋值语句,我们被迫承认时间进入了我们的计算模型。在我们介绍赋值语句前...翻译 2018-08-14 19:47:52 · 246 阅读 · 0 评论 -
3.4.1 在并发系统中的时间的本性
3.4.1 在并发系统中的时间的本性在表面上,时间似乎是自然的。它强加给事件一个顺序。对于任何一个事件A和B,或者是A在B前, B在A前, A和B是同时的。例如,还是银行账号的例子,假定从一个联合的刚开始有100元的账号中,彼得取10元,保罗取25元,账号中还剩65元。依赖于这两次取款的顺序,在账号中的余额的序列可能是 100—>90->65 或者是100->75-&...翻译 2018-08-14 19:48:59 · 190 阅读 · 0 评论 -
2.3.3 例子:表示集合
2.3.3 例子:表示集合在前面的例子中,我们构建了两种复合数据的表示法。一种数据是有理数,另一种数据是代数表达式。这些例子中的一个我们化简表达式的选择在组装时或者是选择时。但是其它的情况是为了这些结构的表示法的选择。当我们转到集合的表示时,表示法的选择并不明显。实际上,有一些可能用的表示法。在某些时候,它们之间的区别很大。形式化的讲,一个集合是一个不同的元素组成的。为了得到更精确的...翻译 2018-08-07 10:45:36 · 372 阅读 · 0 评论 -
翻译连载 第2篇 计算机的编程结构与解释
1. 用程序构建抽象精神的作用,在于它通过简单的思想发挥它的威力,是主要有这三个方面:1. 组合一些简单的思想成为一个复合的思想,因此所有的复杂的思想就产生了。2. 第二是把两个思想无论是简单的,还是复杂的,放在一起,让它们从另外的一个的角度,得到它们的另一个方面,而不是把它们整合成一个,而得到与它们有关系的思想。3. 第三是在它们真实存在的领域中把它们从伴随着它们的其它思想中分离出...翻译 2018-08-02 16:06:48 · 175 阅读 · 0 评论 -
翻译连载 第3篇 计算机的编程结构与解释
1.1 编程的元素一个强有力的编程语言,不仅仅是能够让一台计算机执行任务,语言也能提供一个框架,这个框架是让我们用思想来组织起流程。因此,我们在描述一个语言的时候,我们应该特别注意到,语言能够提供一种把简单的思想组合成复杂的思想的方法。为了实现这个任务,每一个强有力的语言都有三种机制。原生的表达式: 什么能够用该语言的最简单的对象表达出来,组装的方法: 什么能够用该语言的简单的...翻译 2018-08-02 16:09:06 · 153 阅读 · 0 评论 -
翻译连载 第4篇 计算机的编程结构与解释
1.1.1 表达式开始编程的一个简单的方式,是用LISP的方言SCHEME的解释器得到一些经典的交互内容。想像一下,你正坐在电脑的终端前,你打了一个表达式,解释器返回了它被执行的的结果。你能够打的原生的表达式的一种是数字。(更准确地说,你打的表达式由10进制的数字组成。) 如果你为LISP提供一个数字486解释器将返回 打印值486表示数字的表达式,可能与表示原生的程序(例...翻译 2018-08-02 16:11:58 · 172 阅读 · 0 评论 -
翻译连载 第5篇 计算机的编程结构与解释
1.1.2 命名与环境变量编程语言的一个关键的方面是,提供 使用名称引用计算对象的方法。我们说名称是标识着一个变量,变量的值是一个对象。在LISP的SCHEME方言中,我们用DEFINE来命名事物。打出如下的内容:(define size 2)能够让解释器把数值2与名称 size 关联起来。size2(* 5 size)10这里有define 使用的进一步的例子:(def...翻译 2018-08-02 16:13:20 · 235 阅读 · 0 评论 -
翻译连载 第6篇 计算机编程的编程结构与解释
1.1.3 评估组合子在这一章中我们的目标是独立出关于程序性的思维的问题。作为一个点的案例,让我们考虑下,在组合的执行中,解释器本身遵循的程序。为了执行一个组合,操作如下:1. 执行组合的子表达式2. 应用 最左子表达式(操作符)的值作为程序名以及它的其它的子表达式(操作数)的值作为实际参数。总之,这个简单的规则展示出关于流程的一些重要的观点。首先,为了完成组合的执行流程,第...翻译 2018-08-02 16:16:08 · 215 阅读 · 0 评论 -
2.3.4 例子:哈夫曼编码树
2.3.4 例子:哈夫曼编码树这部分提供了练习,在列表结构和数据抽象的使用方面,来操纵集合和树。应用的方法是表示数据为1和0的序列。例如,ASCII标准编码用来表示计算机中的文本,编码任何一个字符为七位的一个序列。使用7位比特的长度,允许区分出2^7或者是128个可能的不同的字符。总之,如果我们要区分n个不同的字符,我们将需要为每个字符使用log2(n)个比特的位长。如果我们所有的消息都是由...翻译 2018-08-07 10:47:20 · 1599 阅读 · 0 评论 -
2.4抽象数据的多种表示
2.4抽象数据的多种表示我们已经介绍了数据抽象,结构化系统的在这方面的方法学是程序要能够独立于对程序所操作的数据对象的具体实现的选择。例如,我们在2.1.1中看到的,如何分离出 设计一个使用有理数的程序的任务与通过计算机语言的原生的组合复合数据的机制实现有理数的任务。重要的思想是消除抽象的障碍--在这个例子中,是有理数的选择子与组装子(make-rat,numer,denom)--它隔...翻译 2018-08-07 10:51:00 · 285 阅读 · 0 评论 -
2.4.1 复数的表示
2.4.1 复数的表示我们将开发一个系统来执行复数的算术运算,来作一个简单的例子。但是这个非实际使用的例子也使用了通用性的操作。我们开始讨论用有序数对表示的复数的两种表示形式。平面坐标(实部和虚部)和极坐标(模和角度)。在2。4。2部分中,将能够看到在使用类型标签和通用性的操作后,两种表示法是如何共存于一个系统中的。像有理数一样,复数也能被自然地表示成有序数对。复数的集合能够被看成是有...翻译 2018-08-07 10:53:12 · 521 阅读 · 0 评论