收藏 分享(赏)

程序设计方法.pdf

上传人:HR专家 文档编号:6300665 上传时间:2019-04-05 格式:PDF 页数:423 大小:3.31MB
下载 相关 举报
程序设计方法.pdf_第1页
第1页 / 共423页
程序设计方法.pdf_第2页
第2页 / 共423页
程序设计方法.pdf_第3页
第3页 / 共423页
程序设计方法.pdf_第4页
第4页 / 共423页
程序设计方法.pdf_第5页
第5页 / 共423页
点击查看更多>>
资源描述

1、 如何设计程序 程序设计和计算引论 美 Matthias Felleisen 等著 黄林鹏 朱崇恺 译 人民邮电出版社 2003 I前言 向儿童传授程序设计知识与现代教育学相悖。制定计划、学习教规、注重细节、严格自律有何乐趣? 艾伦佩利(1966年图灵奖获得者),编程警句 许多职业都需要进行某种形式的计算机编程。会计师使用电子表格和字处理软件编程,摄影师使用照片编辑器编程,音乐家使用音响合成器编程,职业程序员使用计算机编程。编程已成为一种人人都需要掌握的技能。 编写程序并不仅仅是一种职业技能,事实上,编程是件有趣的事,是一种创造性的情感发泄,是一种用有形的方式表达抽象思维的方法。设计程序可以教

2、会人们多种技能,如阅读判断、分析思考、综合创造以及关注细节等等,这些技能对各种类型的职业来说都是非常有用的。 所以,在普通教育中,程序设计课程的地位应该和数学、语文一样重要,用更简洁的话来说,就是 每个人都应该学习如何设计程序。 一方面,和数学一样,程序设计可以训练人的分析能力,不同的是,程序设计是一种积极的学习方法,在与软件的互动过程中,学生可以直接得到反馈,进行探索、实验和自我评价。与钻研数学习题相比,程序设计的成果,即计算机软件,更有趣,也更有用,它们能极大地增加学生的成就感;另一方面,和语文一样,设计程序可以增强学生的阅读和写作能力。即使是最小的编程任务,也是以文字形式表达的,没有良好

3、的判断和阅读技能是不可能设计出符合规范的程序,反过来,好的程序设计方法会迫使学生用适当的语言清晰地表达他的思考过程。 基本程序设计步骤 1. 问题分析和数据定义 2. 合约,用途说明与结果的描述,函数头部 3. 例子 4. 函数模板 5. 函数定义 6. 测试 图 0. 1 程序设计的基本步骤 本书是一本程序设计教科书,讨论如何从问题描述产生组织严谨的程序。本书把注意力集中于程序的设计过程,不强调算法和语言细节,不注重于某个特定的应用领域。这门介绍性的程序设计课程有两个根本性的创新,创新之一是给出一系列明确的程序设计指导。现有的程序设计课程往往趋向于给出含糊的、不明确的建议,如“自上而下设计”

4、,或者“结构化程序设计”等,与此不同,本书给出了一系列程序设计指导,由此引导学生一步一步地从问题的描述出发,通过明确定义的中间过程,得出程序。在这个过程中,学生将学会阅读、分析、组织、实验和系统思维能力;创新之二是使用了一个全新的程序设计环境。过去的编程教材往往简单地假设学生有能力使用某种专业程序开发环境,而忽略程序设计环境对学生学习的影响。本书使用的程序设计环境会随着你所掌握的知识的多少而改进,该环境最终可以支持完整的Scheme语言,使用该语言既可以编写大型程序又能编写脚本程序,可以完成所有领域的编程任务。 本书讨论的编程指导以程序设计诀窍 (programming design reci

5、pe)阐述。设计诀窍指导程序设计初II 学者逐步掌握问题求解的过程,有了设计诀窍,程序设计的初学者就不用再盯着空白的纸张或计算机屏幕发呆了,他们可以自我检查并核对设计诀窍,使用“问答”方式进行程序设计并取得进步。 本书通过识别问题的范畴来建立设计诀窍,而问题范畴的识别基于表示相应信息的数据的类型。从该数据类型所描述的结构出发,你可以用一个清单推导出程序。图 0. 1给出的设计诀窍包含了6个程序设计基本步骤,每个步骤都将产生定义明确的中间结果: 1 问题数据类型描述; 2 程序行为的非形式描述; 3 说明程序行为的例子; 4 开发程序的模板或视图; 5 把模板转换成完整的定义; 6 通过测试发现

6、错误。 使用设计诀窍不仅对初学者有所帮助,对教师也有益。教师可以使用清单检查初学者解决问题的能力,诊断错误所在,并提出纠正措施。毕竟,设计诀窍的每一阶段都会产生一个定义明确、可检查的结果。如果一个初学者遇到了困难,教师可以借助清单检查他的中间结果,并判断问题之所在。教师还可以针对程序设计诀窍中某一特定的过程给学生提供指导,提问合适的问题,并推荐额外的练习题。 为什么每个人都应该学习编写程序 想象会把不知名的事物用一种形式呈现出来,诗人的笔再使它们具有如实的形象,空虚的无物也会有了居处和名字。 莎士比亚,仲夏夜之梦V(i) 目前越来越少的人在编写程序代码,主张每个人都应该学习编程似乎有些奇怪。事

7、实上大多数人是在使用应用程序包开发软件,即使是程序员也使用“程序生成器”由规则(如商业规律)创建程序,看起来他们似乎不需要编写代码,那么,为什么还说所有人都应该学习编程呢? 问题的答案可以从两个方面阐述。第一,确实传统形式的编程仅仅对少数人来说是有意义的,但我们这里所讨论的编程模式对每个人,不管是使用电子表格的行政办公室秘书还是高科技公司的程序员,都是有用的。换句话说,这里所讨论的编程概念远比传统的编程观念广泛;第二,本书以最小影响原则来讲授编程思想,着重于分析问题和解决问题的技能,而不是强迫大家掌握一种传统的编程语言或编程工具。 要想更好地理解现代编程思想,请仔细观察一下目前流行的应用程序包

8、,电子表格,如果用户先把描述一个单元A和另一个单元B依赖关系的公式输入电子表格,接着,输入B单元的值,电子表格就会自动计算单元A的值。对于复杂的电子表格,一个单元的值可能依赖多个其他单元,而不仅仅是一个。 其他应用程序包也需要类似的计算。考虑文字处理和样式表软件。样式表说明了如何由待定的词句建立一个(或一部分)文档。当提供了特定的词句之后,文字处理软件就会把样式表中的名字替换为给定的词句,从而建立文档。类似地,某个进行网页检索的人可能会指定若干个关键字、给定关键字之间的顺序以及哪个关键字不必在网页中出现,在这种情况下,搜索结果将取决于搜索引擎的高速缓存和用户所输入的检索表达式。 最后,使用程序

9、生成器的技巧其实就是使用应用程序包的技巧。程序生成器由高层功能描述生成传统程序设计语言代码,例如由商业规律或科学定律产生C+或Java程序,规律把数量、销量或库存记录联系起来并说明计算过程,而程序的其余部分,特别是如何与用户交互以及如何将数据存储于计算机磁盘等等,则几乎或完全不需要人的干预。 所有这些活动都是让计算机软件为我们做某些事,其中一些活动使用科学符号,一些使用固定格式的III自然语言,另一些则使用具体的编程符号,实际上这些活动都是某种形式的编程,其本质可归结如下: 1 把某个量与另一个量相关联, 2 用值代换名进行关系计算。 事实上,上述两个概念刻划了使用最低级的程序设计语言,如机器

10、语言,和使用最流行的程序设计语言,如Java,进行编程的本质。程序将输出和输入相联系,将程序应用于特定的输入,就是在计算中用具体的值代替相关的名字。 没有人可以预知今后五年或是十年内会出现哪种类型的应用程序包,但是,使用应用程序包仍然需要某种形式的编程。要使学生们掌握编程,学校要么强迫他们学习代数,它是编程的数学基础,要么让他们进行某种形式的程序设计活动。有了现代化的程序设计语言和程序设计环境,选择后者可以更有效地完成任务,还可以使代数学习的过程变得更加有趣。 设计诀窍 烹饪既是孩童的游戏也是成人的乐事,细心烹饪是爱的举措。 克雷格卡莱波恩(1920-2000),纽约时报饮食编辑学习设计程序就

11、像学习踢球一样,你必须练习断球、运球、传球和射门。一旦你掌握了这些基本技术,下一个目标就是学习担任某个角色、选择并实施合适的战略,如果没有现成的,你需要创造一种。 程序员和建筑师、作曲家和作家一样,是富有创造性的人,他们从念头和白纸开始,先构思概括,再把它写到纸上,直到写出的东西能充分反映他们的思想为至。他们使用图型、文字或其他方法来表达建筑物风格、描述人的特征或是谱写音乐旋律,他们能胜任自己的职业,是因为经过长时间的练习,他们能本能地使用这些技能。 程序设计者也是先形成程序框架,然后翻译为最初的程序版本,再反复修改,直到与最初的想法相符。事实上,好的程序员会多次编辑和修改自己的程序,最终达到

12、某种形式的美。和足球运动员、建筑师、作曲家和作家一样,他们必须长期练习行业必需的基本技能。 设计诀窍类似于控球技巧、写作技巧、音符编排技巧和绘图技巧。通过学习和研究,在程序设计领域,计算机科学家已经积累了许多重要的方法和技巧,本书挑选了其中最重要和最实用的一些,从简单到容易,逐一讲解。 本书大约有一半的设计诀窍涉及输入数据和程序之间的关系,更准确地说,它们描述了如何从输入数据的类型得出整个程序的模板,这种基于数据驱动的程序设计方式最常见,易于实施、理解、扩展和修改。其他设计诀窍有递归(generative recursion)、累积(accumulation)和历史敏感性(history se

13、nsitivity)。递归型程序可以被重复调用以处理新的问题;聚集型的程序在处理输入的过程中收集数据;历史敏感性程序可以记住程序被多次调用的信息。最后,但不是最不重要的,是抽象程序的设计诀窍。抽象把两个(或更多)相似的程序概括为一个。 在许多场合下,由问题往往会联想到设计诀窍。在另外一些场合下,则必须从几种可能性中作出选择,不同的清单可能会导致不同的程序结构,它们之间的差别可能很大。除非一个程序员十分熟悉所有可选的设计诀窍,完全理解选择某个诀窍而不是另一个诀窍的结果,否则程序设计过程不可避免按事论事,甚至会导致离奇古怪的结果。我们希望通过制订一系列设计诀窍来帮助程序员理解选择什么以及如何进行选

14、择。 上面解释了“编程”和“程序设计”的含义,读者应该理解到本书所讲授的思想方法和技能对多种职业来说都相当重要。要正确地设计程序,你必须: 1 分析通常使用文字表述的问题; 2 在抽象表达问题实质的同时使用例子进行说明; IV 3 用精确的语言阐明所表述的语句和注释; 4 通过检查、测试对上述活动进行评价和修改; 5 关注细节。 所有这些行为对商人、律师、记者、科学家、工程师以及其他人来说都是有用的。 尽管传统意义上的编程也需要这些技巧,但初学者往往不理解它们之间的关系。问题是,传统的程序设计语言以及传统形式的编程需要学生记住许多与特定语言相关的细节。简而言之,琐碎杂事淹没了本质。要避免这个问

15、题,教师必须使用一种适合初学者的程序设计环境,它尽可能不增加学生额外的负担。 选用Scheme和DrScheme 我们把美归于简单, 不含多余部分, 边界清晰, 与一切相关联, 是中庸之道。 拉尔夫沃尔多爱默生,人生苦旅 本书选择Scheme作为教学语言,辅助程序设计环境为DrScheme,软件可以免费从本书官方网站下载。 尽管如此,本书并不是一本介绍Scheme程序设计语言的书籍,它仅涉及部分Scheme结构。具体说来,本书仅使用六种Scheme结构(它们是函数定义和调用、条件表达式、结构体定义,局部定义以及赋值等)以及大约十二个基本函数,它们就是讲授计算和编程原则所需要的全部东西。希望把S

16、cheme当作一种工具来使用的人则需要阅读其它的材料。 对初学者来说,选用Scheme是很自然的。首先,程序员可以把注意力集中于两个要素,即前面所指出的基本编程原则:程序就是数量之间的关系,对于特定的输入求取结果。使用Scheme语言核心,在教师的指导下,学生在第一堂课就可以开发出完整的程序。 其次,可以方便地将Scheme组织成从简单到复杂的一系列不同级别的语言。这个性质对初学者来说是至关重要的。当初学者犯了简单的符号错误时,一般程序设计语言会给出含糊的、与语言高级特征相关的错误信息。初学者往往浪费很多时间来查找错误所在,由此产生学习挫折感。为了避免这些问题,通过持续对赖斯大学计算机实验室的

17、程序设计初学者的观察,经过谨慎选择,DrScheme实现了若干不同层次的Scheme程序设计环境。按照安排,不同的环境会给出与学生当前知识水平相适应的错误信息。更好的是,分层会避免许多基本错误。当学生学习了足够的编程和语言知识后,教师可以建议他们接触更丰富的语言层次,由此编写更有趣、更简练的程序。 另外,DrScheme提供了一个真正的交互式环境。环境由两个窗口组成:一个是定义窗口,在其中可以定义程序,另一个是交互窗口,其行为就像是一个袖珍计算器,你可以在其中输入表达式,由DrScheme求出它们的值。换句话说,计算由袖珍计算器完成,而这是学生们都相当熟悉的。很快,计算形式就从袖珍计算器上的算

18、术运算向前推进,变成对结构体、表和树的计算。事实上,使用交互式的计算方式可以鼓励学生们用各种方法进行程序实验,从而激发他们的好奇心。 最后,使用包含丰富数据结构的交互式程序设计环境可以让学生把注意力集中于问题的解决和程序设计活动之上。关键的改进是,交互式求值环境避免了(几乎是)多余的关于输入和输出的讨论。这一点改进带来了几种结果。第一,掌握输入和输出函数需要记忆,学习这些东西单调乏味、令人厌烦,相反,如果使用固定方式的输入和输出,我们就能将精力集中于问题求解技术的学习;第二,良好的面向文字的输入需要深奥的编程技能,最好从问题求解的课程中学习;三,现代软件一般采用图形用户界面(GUI),GUI是

19、程序员使用编辑器和“向导精灵”设计的 ,不是手工完成的。学生最好学习使用与标尺、按钮、文本框等相关的函数,而不是背诵那些与流行的GUI库相关的特定协议。简而言之,在初次介绍编程时就讨论输V入和输出是对宝贵的学习时间的浪费。如果要进一步学习,掌握必需的Scheme输入输出知识也比较方便。 总而言之,只要少量几节课,学生们就可以学会Scheme语言的核心,这种语言和传统的程序设计语言一样强大。这样,学生立即就可以把注意力集中于编程本质,这将极大增强他们解决一般问题的能力。 本书其余部分 本书由8个部分和7个独立的章节(书中第8、13、18、24、29、33、38章)组成。8个部分主要讨论程序设计,

20、独立章节则介绍一些与程序设计和计算相关的话题。图 0. 2出了本书各部分间的依赖关系,可以看出,你可以按不同的顺序来阅读本书,只阅读部分内容也是可以的。 本书第1至第3部分包括了基于数据驱动的程序设计基础。第4部分介绍了程序设计中的抽象问题。第5部分和第6部分与递归及累积相关。本书前6部分使用了纯函数式(或称代数式)的程序设计风格,即无论计算多少遍,同一个表达式每次计算的结果总是相同。这种特性使程序易于设计,程序性质易于推导。不过,为了处理程序接口和解决其他领域的问题,我们放弃了部分代数性质,引入了赋值语句。本书的最后两部分说明了设计程序的意义,更精确地说,它们阐述了如何应用前6个部分所描述的

21、程序设计诀窍,以及使用赋值语句必须特别小心的一些问题。 独立章节则介绍一般性的、非本质的,但对计算和程序设计来说是重要的话题,有的是在严格的基础上介绍本书所选定的Scheme子集的语法和语义,有的是介绍了另外的程序设计结构。独立章节5讨论了抽象的计算开销(包括时间和空间开销),并介绍了向量的概念。独立章节6则比较了两种数值表示技术以及处理它们的方法。 本书有些内容的学习可以推后,直到需要。这一点对于学习与Scheme语法和语义相关的独立章节尤为确切。但是,考虑到图 0. 2中第18章的重要地位,我们应该及时学习。 程序的逐步求精:系统化程序设计方法对于开发大型项目特别有意义,也特别重要。而开发

22、单一函数到小规模的包括多个函数的项目则需要另外一种设计思想:逐步求精,即先设计程序核心,再增加功能,直至满足整个需求目标为止。 学习完第一节课后同学就应该有了程序逐步求精的初步印象。为了使学生熟悉这种技术,书中给出了许多补充练习,这些使用简短概述引出的练习可以指导学生进行程序逐步求精的训练。第16章将明确阐述这种思想。 另外,本书会重复使用某些练习和例子。例如,第6.6节、第7.4节、第10.3节、第21.4节、第41.4节以及最后二节中的一些练习题都涉及了如何在画布上移动图像的问题。这样,学生就会多次看到同样的问题,而每一次讨论都会增加他们对程序组织的了解。 本书通过逐步把功能加到一个程序体

23、中的方法来示范为什么程序员必须遵循设计诀窍,借助问题的解决方式向学生展示如何在可用的设计诀窍中进行选择。有时候新知识的作用只是帮助学生改进程序的组织结构,换句话说,要让学生了解到在他们初步的工作完成之后,编程过程并没有结束,如撰写论文和书籍一样,程序也需要进一步的编辑和修改。 TeachPack(教学软件包):完成工程项目的一个要求是程序员必须进行团队合作。在程序设计教学环境下,这意味着一个学生写的程序必须与另一个学生编写的程序相匹配。为了模仿“与另一个程序相配”这一概念,本书提供了DrScheme教学软件包TeachPack。粗略地说,教学软件包模仿了一个合作者,由此可以避免由于合作者程序存

24、在错误而带来的不便。技术性的说法是,工程总是由视图和模型两个部分组成,在典型的环境下,学生设计模型,教学包则提供视图。通常,教学包以(图形)用户界面的形式提供视图。事实上,这种分离模仿的是真实世界中的工程分工。 为了使模型与视图相符,学生必须注意函数的规范,必须遵循设计诀窍。对程序员来说,使模型与视图相符是一种非常重要的技能,但程序设计的初级课程常常未能给予足够的重视。在第4部分,为了说明创建GUI的过程并不神秘,我们将说明如何建立一些简单的GUI,以及GUI事件是如何触发函数调用的,但我们不会把很多时间花费在一个需要死记硬背,只需很少思考的主题上。 VI 图 0. 2 本书各部分和独立章节之

25、间的依赖关系 进度:根据需要,每个学校都可以有自己的教学进度表。在赖斯大学,讲授整本教材以及其他一些附加材料通常需要一个学期的时间。一个研究性大学的教师可以使用类似的进度。而高中教师就必须放慢进度。许多尝试使用本教材的高中教师在一个学期内完成了前三个部分的教学;而少数高中只使用本书第一部分,从计算的角度讲授代数问题的求解;另一些高中则用一年的时间教完整本书。要得到有关教学进度表的更多信息,请访问本书的网站。 本书站点:本书有两种版本:纸印本以及在网站 http:/www.htdp.org/ 可以免费获得的电子版本。 网站提供了一些附加材料,包括前面提到过的各种类型的补充练习。目前网站提供有可视

26、化的小球游戏模拟,更多的练习将在不久的将来加入网站。 致谢 本书特别感谢四个人:罗伯特科克卡特赖特,他与本书的第一个作者合作开发了赖斯大学此入门性课程的前身;丹尼尔P弗里德曼,他在1984年要求本书的第一个作者重写了The Little LISPer(由麻省理工学院出版社发行),而这也是本书写作计划的开始;约翰克莱门特,他负责设计、实现和维护DrScheme软件;还有保罗斯特克勒,他忠实地支持我们,帮助我们开发所需的程序设计工具组件。 有许多友人和同事帮助我们开发这本教材,他们在自己的课堂上使用本教材,并且/或者对本书的初稿给出具体的评论。我们对他们的帮助和耐心表示感谢,这些人包括伊恩巴兰德,

27、约翰克莱门特,布鲁斯迪拜,迈克厄恩斯特,凯瑟菲尔勒,丹尼尔P弗里德曼, 约翰格林纳, 约翰斯通, 杰拉尔丁莫林和瓦尔迪马忒们。 在赖斯大学,本书草稿在课程Comp 210上使用了12次,学生们提出了许多宝贵意见。众多第一部分 第二部分 第三部分 第五部分第七部分第四部分18章第六部分第八部分13章 8章 24章29章38章 33章 VIITeachScheme! 研讨会的参加者在他们的课堂上使用了本书的最初草稿,他们中的许多人提出了评论和建议。作为其中代表,这里列出一些作出过积极贡献的人,他们是:巴巴拉阿德勒女士, 斯蒂芬布洛赫先生,杰克克莱先生,理查德克莱门斯博士,凯尔吉列先生,克伦布拉斯女

28、士,马文赫男得先生,迈克尔亨特先生,克伦诺斯女士,贾明雷蒙德先生以及罗伯特里德。克里斯托弗费雷荪和他的父亲耐心地参与了本书前几个部分的工作,让我们直接了解到了年轻学生的观点。感谢你们中的每一位。 最后,Matthias在这里表达他对海尔格的感激,感谢她多年以来的耐心,感谢她为一个心不在焉的丈夫和父亲建立了一个家庭。Robby要感谢黄清薇(音译)的支持和鼓励,没有她,他不可能完成任何事。Matthew感谢袁文(音译)对他忠诚的支持和不朽的音乐。Shriram感激凯瑟菲尔勒的支持、忍耐和所说的双关语,同时对她参与本书部分工作表示感谢。i 目录 前言I 为什么每个人都应该学习编写程序 II 设计诀窍

29、.III 选用Scheme和DrScheme.IV 本书其余部分 V 致谢.VI 目录i 第一部分 简单数据的处理1 第1章 学生,教师和计算机.1 第2章 数、表达式和简单程序.2 21 数和算术运算2 22 变量和程序.3 23 字处理问题.6 24 错误.6 25 设计程序.8 第3章 程序就是函数加上变量定义.10 31 函数复合. 11 32 变量定义.13 33 复合函数练习.14 第4章 条件表达式和函数15 41 布尔类型和关系.15 42 函数和测试条件.17 43 条件和条件函数.20 44 条件函数的设计.22 第5章 非数值信息25 51 符号的手工练习.27 第6章

30、复合数据之一,结构体.28 61 结构体28 62 补充练习:绘制简单图形.30 63 结构体定义.32 64 数据定义.35 65 设计处理复合数据的函数.36 66 补充练习: 圆和长方形的移动40 67 补充练习:刽子手游戏.44 第7章 数据的多样性45 71 数据混合与区分.46 72 设计处理混合数据的函数.49 73 再论函数复合.52 74 补充练习:图形的移动.55 75 输入错误.55 ii第8章 语法和语义57 81 Scheme的词汇.57 82 Scheme的文法.58 83 Scheme的含义.59 84 错误.62 85 布尔值表达式.64 86 变量定义.65

31、87 结构体的定义.66 第二部分 任意数目数据的处理69 第9章 复合数据类型之二:表.69 91 表.69 92 任意长的表的数据定义.72 93 处理任意长的表.73 94 处理自引用数据的函数.75 95 更多关于简单表的例子.77 第10章 表的进一步处理80 101 返回表的函数.80 102 包含结构体的表.84 103 补充练习:移动图像.88 第11章 自然数89 111 定义自然数.90 112 处理任意大的自然数.91 113 补充练习:创建表,测试函数93 114 自然数的另一种数据定义94 115 更多与自然数有关的性质98 第12章 三论函数复合99 121 设计复

32、杂的程序.99 122 递归的辅助函数.100 123 问题泛化与函数泛化.103 124 补充练习:字母的重新排列.106 第13章 用list构造表.108 第三部分 再论任意大数据的处理 112 第14章 再论自引用数据定义. 112 141 结构体中的结构体. 112 142 补充练习: 二叉搜索树. 118 143 表中的表.121 144 补充练习: Scheme求值123 第15章 相互引用的数据定义.124 151 由结构体组成的表,结构体中的表125 152 为相互引用的定义设计函数.129 153 补充练习:网页再谈.131 第16章 反复精化设计131 161 数据分析.

33、132 162 定义数据类型,再改进它们.133 iii 163 改进函数和程序.135 第17章 处理两种复杂数据136 171 同时处理两个表:第一种情况.136 172 同时处理两个表:第二种情况.138 173 同时处理两个表:第三种情况.140 174 函数的简化.143 175 设计读入两个复杂输入的函数.144 176 处理两个复杂输入的练习.145 177 补充练习: Scheme求值之二148 178 相等与测试.149 第18章 局部定义和词汇的范围.155 181 用local组织程序.155 182 辖域和块结构.166 第四部分 抽象设计170 第19章 定义的相似性

34、170 191 函数的类似之处.170 192 数据定义的类似之处.176 第20章 函数也是值179 201 语法和语义.180 202 抽象和多态函数的合约.181 第21章 抽象设计的例子184 211 从实例中抽象.184 212 抽象表处理函数的练习.188 213 抽象与唯一控制点.189 214 补充练习:再论移动图像.190 215 注意:由模板设计抽象.191 第22章 使用函数设计抽象192 221 返回函数的函数.193 222 把函数当成值来设计抽象.194 223 图形用户界面初探.196 第23章 数学方面的例子201 231 数列和级数.202 232 等差数列和

35、等差级数.203 233 等比数列和等比级数.204 234 函数曲线下方的面积.206 235 函数的斜率.208 第24章 定义匿名函数212 241 lambda表达式的语法.212 242 lambda表达式的辖域和语义.213 243 lambda表达式的语用.215 第五部分 生成递归216 第25章 一种新的递归形式216 251 为桌上的一个球建立模型.216 252 快速排序.219 iv第26章 设计算法222 261 终止.223 262 结构递归和生成递归的比较.226 263 做出选择.226 第27章 主题的变更229 271 分形.230 272 从文件到行,从表

36、到表的表.234 273 二分查找.237 274 牛顿法.241 275 补充练习: 高斯消去法.242 第28章 回溯算法246 281 图的遍历.246 282 补充练习: 皇后之间的相互阻碍250 第29章 计算的代价、向量251 291 具体的时间和抽象的时间.252 292 “阶”的定义.255 293 向量初探.257 第六部分 知识累积266 第30章 知识的丢失266 301 一个关于结构处理的问题.266 302 一个关于生成递归的问题.269 第31章 设计带累积器的函数.271 311 认识累积器的必要性.272 312 带累积器的函数.272 313 把函数转换成带累

37、积器的变体.274 第32章 使用累积器的更多例子.281 321 补充练习:有关树的累积器.281 322 补充练习:传教士和食人者问题285 323 补充练习:单人跳棋.287 第33章 非精确数的本质288 331 固定长度的数的算术运算.288 332 上溢出.292 333 下溢出.292 334 DrScheme数.293 第七部分 改变变量的状态295 第34章 函数的记忆295 第35章 对变量赋值298 351 简单的、能工作的赋值.298 352 顺序计算表达式.299 353 赋值和函数.301 354 第一个有用的例子.303 第36章 设计有记忆的函数305 361

38、对记忆的需求.305 362 记忆与状态变量.306 v 363 初始化记忆的函数.307 364 改变记忆的函数.308 第37章 使用记忆的例子312 371 状态的初始化.312 372 与用户交互并改变状态.314 373 在递归中改变状态.321 374 状态变量的练习.325 375 补充练习:探索.326 第38章 最终的语法和语义328 381 Advanced Scheme的词汇328 382 Advanced Scheme的语法328 383 Advanced Scheme的含义330 384 Advanced Scheme中的错误.340 第八部分 复合值的改变344 第

39、39章 封装344 391 状态变量的抽象.344 392 封装练习.351 第40章 可改变的结构体352 401 由函数得出结构体.353 402 可变泛函结构体.355 403 可变的结构体.357 404 可变的向量.362 405 改变变量,改变结构体.363 第41章 设计改变结构体的函数.366 411 为什么改变结构体.366 412 结构体的设计诀窍与变化器之一367 413 结构体的设计诀窍与变化器之二375 414 补充练习:最后一次移动图像.384 第42章 相等384 421 外延相等.384 422 内涵相等.385 第43章 修改结构体、向量和对象.387 431

40、 关于向量的更多练习.387 432 循环结构体的收集.398 433 状态的回溯.406 结语.408 计算.408 程序设计.408 与时俱进.409 61 第一部分 简单数据的处理 第1章 学生,教师和计算机 大家从孩童就开始学习计算,最初仅仅是数的加减,如 1加1等于2,5减2等于3。 随着年龄的增加,大家学到了更多的数值运算,如指数和三角函数等,也学到了如何描述计算规则,如 给定一个圆的半径r,它的周长是r乘以2。一个劳动者工作N个小时所获得的最低报酬是N乘以5.35。 可以说是教师将我们变为计算机,让我们执行简单的计算机程序。 因此,计算本身并没有秘密可言。程序仅仅是计算速度非常之

41、快的学生。当我们在思考第一道题目的时候它却可以完成百万道加法运算。但是,计算机所能做的事远比进行数值计算多的多,它可以给飞机导航,可以作为一个游戏的参与者,可以查询一个人的电话号码,也可以打印一个大公司的薪水册。简而言之,计算机可以处理所有类型的信息。 人类可以使用自然语言描述信息和指令,如 当前温度是35oC, 请将其转换为华氏温度值。引擎花了35秒将汽车速度从零加速到100英里,请确定在20秒时汽车的速度。 而计算机,基本不懂自然语言,也无法理解以自然语言表示的复杂指令。因此为了向计算机传达信息和指令,我们不得不学习一种计算机语言。 表示指令和信息的计算机语言就是程序设计语言。以程序设计语

42、言表示的信息称为数据。有许多种类型的数据,如数是一种数据,而数列也是一种数据,但后者属于复合数据,因为每个数列都由较小单位的数据,即数,组成。为了区分这两种类型的数据,前者称为原子数据。字母是另一种类型的原子数据,而家族树则是一种复合数据。 虽然数据表示信息,但它们的具体解释则依赖于我们,如数37.51可能表示一个温度,也可能表示时间或距离。而字符“A”可以表示学习成绩,食品的质量或一个地址的一部分。 如同数据,指令,也称为操作,也有不同的风格。 每类数据都与一个基本操作集相关联。例如数,相关的操作有、等。程序设计者将基本操作组合成程序。因此,可以将基本操作想象为某一外国语言中的单字,而将程序

43、设计想象为在这种语言中遣词造句。 一些程序如同散文般简短,而另一些却如同百科全书般殷实。撰写散文和书籍需要细心的策划,编写程序也是如此,不管大小,一个好的程序不可能是修修补补的结果,它必须经过精心设计,每一部分都需要关注,要将简单程序组成一个更大的单位还必须遵循预定的策略。因此设计好的程序必须从程序设计的最初实践开始。 在本书中,我们将学习如何设计计算机程序以及理解它们的功能。成为一个程序设计者是有意义的,但不是一件容易的事。最好的方式是看着我们的“孩子”逐渐长大并获得成功。看到自己设计的计算机程序能帮助他人,很兴奋,对吗?但为了做到这点,你必须先学习许多技术。我们将看到,程序设计语言是简单的

44、,其语法是严格定义的,但不幸的是,计算机是愚蠢的,极小的一个程序语法错误对于计算机来说也是致命的。而更坏的是,就算程序合乎文法,它也不一定如预期的那样完成计算任务。 程序设计需要耐心和专心,只有关注每个微小的细节才能避免沮丧的语法错误,只有严格的规划和对规划的忠诚才能在设计中防止严重的逻辑错误。当你最终掌握程序设计的时候,你将学到超越程序设计领域的许多有用知识。 让我们开始吧! 2第2章 数、表达式和简单程序 在计算机诞生的初期,人们将其想象为处理数值的机器,实际上,计算机也善于数值处理。既然小学一年级老师最先讲的是数的运算,本书也从数开始。一旦了解计算机如何进行数值计算,只要将常识转换为程序

45、语言记法,我们就可以开发简单的计算机程序了。尽管如此,编写简单的程序也是需要原则的,因此本章的最后将介绍最基本的程序设计指导。 21 数和算术运算 数有多种形式, 正数、负数、分数(也称有理数)和实数是最常见的数: 5 -5 2/3 17/3 #i1.4142135623731 其中第1个数是正数,第2个数是负数,接着是两个分数,最后一个是实数的非精确表示。 如同使用最简单的计算机,即计算器,在Scheme中你也可以对数进行加减乘除运算: (+ 5 5) (+ -5 5) (+ 5 -5) (- 5 5) (* 3 4) (/ 8 12) 其中前3个表达式要求Scheme执行加法运算,后3个表

46、达式则分别是减法、乘法和除法运算。所有表达式都使用了括号,其中操作在前,接着是以空格隔开的操作数。 与算术、代数公式类似,Scheme表达式也可以嵌套使用: (* (+ 2 2) (/ (* (+ 3 5) (/ 30 10) 2) Scheme对这些表达式的计算与算术一样,首先将最内层的表达式计算为数值,然后是外面一层,以此类推: (* (+ 2 2) (/ (* (+ 3 5) (/ 30 10) 2) = (* 4 (/ (* 8 3) 2) = (* 4 (/ 24 2) = (* 4 12) = 48 由于每个表达式的形式皆为 (operation A . B) 因此不存在那部分先进

47、行计算的问题。当A . B都是数的时候,就可以对表达式进行计算了,否则需要先对A . B进行计算,与 345 相对照,这是一个小学时就遇到的表达式,在作了大量的练习后大家记得了在计算的时候应该先乘除后加减。1最后,Scheme不仅包括简单的数学运算还提供了一整套高级数学运算,这是5个例子: 1. (sqrt A) 计算(A)1/2; 2. (expt A B) 计算AB; 3. (remainder A B) 计算整数A除以整数B的余数; 1Scheme语言的另一个优点是我们总知道在那里放置或找到操作符,它紧挨者一个左括号。 3 4. (log A) 计算A的自然对数; 5. (sin A)

48、计算弧度A的正弦值。 如果怀疑一个基本运算是否存在或欲了解其使用方式,请使用简单的例子在DrScheme上进行测试。 关于数:在Scheme可以使用产生精确结果的基本操作对精确整数和有理数进行计算。因此,(/ 44 14) 的结果是 22/7。不幸的是,当涉及实数的时候,和其他程序语言一样,Scheme在精度上做了折中考虑。例如,2的平方根是一个实数而不是一个有理数,因此Scheme不得不使用不精确数来表示它: (sqrt 2) = #i1.4142135623731 其中#i 警告程序设计者,计算结果是真正数值的一个近似表示。一旦一个不精确数成为计算的一部分,计算过程将以近似的方式进行, 如

49、: (- #i1.0 #i0.9) = #i0.09999999999999998 而 (- #i1000.0 #i999.9) = #i0.10000000000002274 但从数学上看,两者的结果都应是0.1,是相等的,因此一旦一个数是非精确的,系统应给出警告。 造成非精确的原因是用简化的方式表示2的平方根或如这样的数值,实际上这些数的十进制表示是无限长的(不含循环),而在一台计算机中,数的表示长度是有限的,因此只能表示这些数的一部分。如果将这些数表示为固定长度的有理数,其结果必然是非精确的。第33章将讨论非精确数是如何工作的。 为了集中精力学习与计算相关的重要概念而不是拘泥于这些细节,DrScheme会尽量将数处理为精确数。如在DrScheme中输入1.25,系统会将该数解释为一个

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报