logo资料库

ANSI COMMON LISP 中文译本.pdf

第1页 / 共266页
第2页 / 共266页
第3页 / 共266页
第4页 / 共266页
第5页 / 共266页
第6页 / 共266页
第7页 / 共266页
第8页 / 共266页
资料共266页,剩余部分请下载后查看
前言
这本书面向的读者
如何使用这本书
代码
On Lisp
鸣谢
Chapter 1 简介 (Introduction)
1.1 新的工具 (New Tools)
1.2 新的技术 (New Techniques)
1.3 新的方法 (New Approach)
Chapter 2 欢迎来到 Lisp (Welcome to Lisp)
2.1 形式 (Form)
2.2 求值 (Evaluation)
2.3 数据 (Data)
2.4 列表操作 (List Operations)
2.5 真与假 (Truth)
2.6 函数 (Functions)
2.7 递归 (Recursion)
2.8 阅读 Lisp (Reading Lisp)
2.9 输入输出 (Input and Output)
2.10 变量 (Variables)
2.11 赋值 (Assignment)
2.12 函数式编程 (Functional Programming)
2.13 迭代 (Iteration)
2.14 作为对象的函数 (Functions as Objects)
2.15 类型 (Types)
2.16 展望 (Looking Forward)
Chapter 2 总结 (Summary)
Chapter 2 习题 (Exercises)
Chapter 3 列表 (Lists)
3.1 构建 (Conses)
3.2 等式 (Equality)
3.3 为什么 Lisp 没有指针 (Why Lisp Has No Pointers)
3.4 建立列表 (Building Lists)
3.5 示例:压缩 (Example: Compression)
3.6 存取 (Access)
3.7 映射函数 (Mapping Functions)
3.8 树 (Trees)
3.9 理解递归 (Understanding Recursion)
3.10 集合 (Sets)
3.11 序列 (Sequences)
3.12 栈 (Stacks)
3.13 点状列表 (Dotted Lists)
3.14 关联列表 (Assoc-lists)
3.15 示例:最短路径 (Example: Shortest Path)
3.16 垃圾 (Garbages)
Chapter 3 总结 (Summary)
Chapter 3 习题 (Exercises)
Chapter 4 特殊数据结构 (Specialized Data Structure)
4.1 数组 (Array)
4.2 示例:二叉搜索 (Example: Binary Search)
4.3 字符与字串 (Strings and Characters)
4.4 序列 (Sequences)
4.5 示例:解析日期 (Example: Parsing Dates)
4.6 结构 (Structures)
4.7 示例:二叉搜索树 (Example: Binary Search Tree)
4.8 哈希表 (Hash Table)
Chapter 4 总结 (Summary)
Chapter 4 习题 (Exercises)
Chapter 5 控制流 (Control)
5.1 区块 (Blocks)
5.2 语境 (Context)
5.3 条件 (Conditionals)
5.4 迭代 (Iteration)
5.5 多值 (Multiple Values)
5.6 中止 (Aborts)
5.7 示例:日期运算 (Example: Date Arithmetic)
Chapter 5 总结 (Summary)
Chapter 5 练习 (Exercises)
Chapter 6 函数 (Functions)
6.1 全局函数 (Global Functions)
6.2 局部函数 (Local Functions)
6.3 参数列表 (Parameter Lists)
6.4 示例:实用函数 (Example: Utilities)
6.5 闭包 (Closures)
6.6 示例:函数构造器 (Example: Function Builders)
6.7 动态作用域 (Dynamic Sc​​ope)
6.8 编译 (Compilation)
6.9 使用递归 (Using Recursion)
Chapter 6 总结 (Summary)
Chapter 6 练习 (Exercises)
Chapter 7 输入与输出 (Input and Output)
7.1 流 (Streams)
7.2 输入 (Input)
7.3 输出 (Output)
7.4 示例:字串代换 (Example: String Substitution)
7.5 宏字符 (Macro Characters)
Chapter 7 总结 (Summary)
Chapter 7 练习 (Exercises)
Chapter 8 符号 (Symbols)
8.1 符号名 (Symbol Names)
8.2 属性列表 (Property Lists)
8.3 符号很不简单 (Symbols Are Big)
8.4 创建符号 (Creating Symbols)
8.5 多重包 (Multiple Packages)
8.6 关键字 (Keywords)
8.7 符号与变量 (Symbols and Variables)
8.8 示例:随机文本 (Example: Random Text)
Chapter 8 总结 (Summary)
Chapter 8 练习 (Exercises)
Chapter 9 数字 (Numbers)
9.1 类型 (Types)
9.2 转换及取出 (Conversion and Extraction)
9.3 比较 (Comparison)
9.4 算术 (Arithematic)
9.5 指数 (Exponentiation)
9.6 三角函数 (Trigometric Functions)
9.6 三角函数 (Trigometric Functions)
9.7 表示法 (Representations)
9.8 范例:追踪光线 (Example: Ray-Tracing)
Chapter 9 总结 (Summary)
Chapter 9 练习 (Exercises)
Chapter 10 宏 (Macros)
10.1 求值 (Eval)
10.2 宏 (Macros)
10.3 反引号 (Backquote)
10.4 示例:快速排序法(Example: Quicksort)
10.5 设计宏 (Macro Design)
10.6 通用化参照 (Generalized Reference)
10.7 示例:实用的宏函数 (Example: Macro Utilities)
10.8 源自 Li​​sp (On Lisp)
Chapter 10 总结 (Summary)
Chapter 10 练习 (Exercises)
Chapter 11 Common Lisp 对象系统 (CLOS)
11.1 面向对象编程 Object-Oriented Programming
11.2 类与实例 (Class and Instances)
11.3 槽的属性 (Slot Properties)
11.4 基类 (Superclasses)
11.5 优先级 (Precedence)
11.6 通用函数 (Generic Functions)
11.7 辅助方法 (Auxiliary Methods)
11.8 方法组合机制 (Method Combination)
11.9 封装 (Encapsulation)
11.10 两种模型 (Two Models)
Chapter 11 总结 (Summary)
Chapter 11 练习 (Exercises)
Chapter 12 结构 (Structure)
12.1 共享结构 (Shared Structure)
12.2 修改 (Modification)
12.3 示例:队列 (Example: Queues)
12.4 破坏性函数 (Destructive Functions)
12.5 示例:二叉搜索树 (Example: Binary Search Trees)
12.6 示例:双向链表 (Example: Doubly-Linked Lists)
12.7 环状结构 (Circular Structure)
12.8 常量结构 (Constant Structure)
Chapter 12 总结 (Summary)
Chapter 12 练习 (Exercises)
Chapter 13 速度 (Speed)
13.1 瓶颈规则 (The Bottleneck Rule)¶
13.2 编译 (Compilation)
13.3 类型声明 (Type Declarations)
13.4 避免垃圾 (Garbage Avoidance)
13.5 示例: 存储池 (Example: Pools)
13.6 快速操作符 (Fast Operators)
13.7 二阶段开发 (Two-Phase Development)
Chapter 13 总结 (Summary)
Chapter 13 练习 (Exercises)
Chapter 14 进阶议题 (Advanced Topics)
14.1 类型标识符 (Type Specifiers)
14.2 二进制流 (Binary Streams)
14.3 读取宏 (Read-Macros)
14.4 包 (Packages)
14.5 Loop 宏 (The Loop Facility)
14.6 状况 (Conditions)
Chapter 15 示例:推论 (Example: Inference)
15.1 目标 (The Aim)
15.2 匹配 (Matching)
15.3 回答查询 (Answering Queries)
15.4 分析 (Analysis)
Chapter 16 示例:生成 HTML (Example: Generating HTML)
16.1 超文本标记语言 (HTML)
16.2 HTML 实用函数 (HTML Utilities)
16.3 迭代式实用函数 (An Iteration Utility)
16.4 生成页面 (Generating Pages)
Chapter 17 示例:对象 (Example: Objects)
17.1 继承 (Inheritance)
17.2 多重继承 (Multiple Inheritance)
17.3 定义对象 (Defining Objects)
17.4 函数式语法 (Functional Syntax)
17.5 定义方法 (Defining Methods)
17.6 实例 (Instances)
17.7 新的实现 (New Implementation)
17.8 分析 (Analysis)
Appendix A 调试 (Debugging)
中断循环 (Breakloop)
追踪与回溯 (Traces and Backtraces)
当什么事都没发生时 (When Noting Happens)
没有值或未绑定 (No Value/Unbound)
意料之外的 Nil (Unexpected Nils)
重新命名 (Renaming)
作为选择性参数的关键字 (Keywords as Optional Parameters)
错误声明 (Misdeclarations)
警告 (Warnings)
Appendix B. Lisp in Lisp
Notes 备注
备注 viii (Notes viii)
备注 1 (Notes 1)
备注 3 (Notes 3)
备注 4 (Notes 4)
备注 5 (Notes 5)
备注 5-2 (Notes 5-2)
备注 12 (Notes 12)
备注 17 (Notes 17)
备注 26 (Notes 26)
备注 28 (Notes 28)
备注 46 (Notes 46)
备注 61 (Notes 61)
备注 62 (Notes 62)
备注 76 (Notes 76)
备注 81 (Notes 81)
备注 84 (Notes 84)
备注 89 (Notes 89)
备注 91 (Notes 91)
备注 94 (Notes 94)
备注 95 (Notes 95)
备注 100 (Notes 100)
备注 100-2 (Notes 100-2)
备注 106 (Notes 106)
备注 109 (Notes 109)
备注 109-2 (Notes 109-2)
备注 112 (Notes 112)
备注 123 (Notes 123)
备注 125 (Notes 125)
备注 141 (Notes 141)
备注 141-2 (Notes 141-2)
备注 150 (Notes 150)
备注 164 (Notes 164)
备注 173 (Notes 173)
备注 176 (Notes 176)
备注 178 (Notes 178)
备注 178 (Notes 178)
备注 183 (Notes 183)
备注 191 (Notes 191)
备注 204 (Notes 204)
备注 213 (Notes 213)
备注 214 (Notes 214)
备注 216 (Notes 216)
备注 217 (Notes 217)
备注 218 (Notes 218)
备注 219 (Notes 219)
备注 224 (Notes 224)
备注 229 (Notes 229)
备注 230 (Notes 230)
备注 239 (Notes 239)
备注 242 (Notes 242)
备注 248 (Notes 248)
备注 276 (Notes 276)
备注 284 (Notes 284)
备注 284-2 (Notes 284-2)
原始文档来自:https://ansi-common-lisp.readthedocs.org/en/latest/ 感谢他们的辛勤付出。 前言 本书的目的是快速及全面的教你 Common Lisp 的有关知识。它实际上包含两本书。前半 部分用大量的例子来解释 Common Lisp 里面重要的概念。后半部分是一个最新 Common Lisp 辞典,涵盖了所有 ANSI Common Lisp 的操作符。 这本书面向的读者 ANSI Common Lisp 这本书适合学生或者是专业的程序员去读。本书假设读者阅读前没有 Lisp 的相关知识。有别的程序语言的编程经验也许对读本书有帮助,但也不是必须的。本 书从解释 Lisp 中最基本的概念开始,并对于 Lisp 最容易迷惑初学者的地方进行特别的强 调。 本书也可以作为教授 Lisp 编程的课本,也可以作为人工智能课程和其他编程语言课程中, 有关 Lisp 部分的参考书。想要学习 Lisp 的专业程序员肯定会很喜欢贯穿于本书中,着眼 于实践的理念。那些已经在使用 Lisp 编程的人士也会发现,本书里面有许多很好的实例可 供参考,此外,本书也是一本很方便的 ANSI Common Lisp 参考书。 如何使用这本书 学习 Lisp 最好的办法就是拿它来编程。况且在学习的同时用你学到的技术进行编程,也是 非常有趣的一件事。编写本书的目的就是让读者尽快的入门,在对 Lisp 进行简短的介绍之 后, 第 2 章开始用 21 页的内容,介绍了着手编写 Lisp 程序时可能会用到所有知识。 3-9 章讲解了 Lisp 里面一些重要的知识点。这些章节特别强调了一些重要的概念,比如指针在 Lisp 扮演的角色,如何使用递归来解决问题,以及第一级函数的重要性。 针对那些想要更深入了解 Lisp 的读者: 10-14 章包含了宏、CLOS、列表操作、程序优化, 以及一些更高级的课题,比如包和读取宏。 15-17 章用 3 个 Common Lisp 的实际应用,总结了之前章节所讲解的知识:一个是进行 逻辑推理的程序,另一个是 HTML 生成器,最后一个是针对面向对象编程的嵌入式语言。 本书的最后一部分包含了 4 个附录,这些附录应该对所有的读者都有用: 附录 A-D 包括了 一个如何调试程序的指南, 58 个 Common Lisp 操作符的源程序,一个关于 ANSI Common Lisp 和以前的 Lisp 语言区别的总结,以及一个包括所有 ANSI Common Lisp 的参考手册。
本书还包括了一部分的备注。这些备注包括一些说明,一些参考条目,一些额外的代码,以 及一些对偶然出现的不正确表述的纠正。备注在文中用一个小圆圈来表示,像这样:○
Tip 译注: 由于小圈圈 ○ 实在太不明显了,译文中使用 λ 符号来表示备注。 λ 代码 虽然本书介绍的是 ANSI Common Lisp ,但是本书中的代码可以在任何版本的 Common Lisp 中运行。那些依赖 Lisp 语言新特性的例子的旁边,会有注释告诉你如何把它们运行于 旧版本的 Lisp 中。 本书中所有的代码都可以在互联网上下载到。你可以在网络上找到这些代码,它们还附带着 一个免费软件的链接,一些过去的论文,以及 Lisp 的 FAQ 。还有很多有关 Lisp 的资源可 以在此找到: http://www.eecs.harvard.edu/onlisp/ 源代码可以在此 FTP 服务器上下载: ftp://ftp.eecs.harvard.edu:/pub/onlisp/ 读者的问题和意见可以发送到 pg@eecs.harv ard.edu 。 Tip 译注:下载的链接都坏掉了,本书的代码可以到此下载: http://lib.store.yahoo.net/lib/paulgraham/acl2.lisp On Lisp 在整本 On Lisp 书中,我一直试着指出一些 Lisp 独一无二的特性,这些特性使得 Lisp 更 像 “Lisp” 。并展示一些 Lisp 能让你完成的新事情。比如说宏: Lisp 程序员能够并且经常 编写一些能够写程序的程序。对于程序生成程序这种特性,因为 Lisp 是主流语言中唯一一 个提供一些方便的抽象,让你完成这个任务的程序语言,所以 Lisp 是主流语言中唯一一个 广泛运用这个特性的语言。我非常乐意邀请那些想要更进一步了解宏和其他高级 Lisp 技术 的读者,读一下本书的姐妹篇: On Lisp 。 Tip On Lisp 已经由知名 Lisp 黑客 –– 田春 –– 翻译完成,可以在网络上找到。 –– 田春(知名 Lisp 黑客、Practical Common Lisp 译者) 鸣谢 在所有帮助我完成这本的朋友当中,我想特别的感谢一下 Robert Morris 。他的重要影响 反应在整本书中。他的良好影响使这本书更加优秀。本书中好一些实例程序都源自他手。这 些程序包括 138 页的 Henley 和 249 页的模式匹配器。 我很高兴能有一个高水平的技术审稿小组:Skona Brittain, John Foderaro, Nick Levine, Peter Norvig 和 Dave Touretzky。本书中几乎所有部分都得益于它们的意见。 John Foderaro 甚至重写了本书 5.7 节中一些代码。
另外一些人通篇阅读了本书的手稿,它们是:Ken Anderson, Tom Cheatham, Richard Fateman, Steve Hain, Barry Margolin, Waldo Pacheco, Wheeler Ruml 和 Stuart Russell。特别要提一下,Ken Anderson 和 Wheeler Ruml 给予了很多有用的意见。 我非常感谢 Cheatham 教授,更广泛的说,哈佛,提供我编写这本书的一些必要条件。另 外也要感谢 Aiken 实验室的人员:Tony Hartman, Dave Mazieres, Janusz Juda, Harry Bochner 和 Joanne Klys。 我非常高兴能再一次有机会和 Alan Apt 合作。还有这些在 Prentice Hall 工作的人士: Alan, Mona, Pompili Shirley McGuire 和 Shirley Michaels, 能与你们共事我很高兴。 本书用 Leslie Lamport 写的 LaTeX 进行排版。LaTeX 是在 Donald Knuth 编写的 TeX 的基础上,又加了 L.A.Carr, Van Jacobson 和 Guy Steele 所编写的宏完成。书中的图表 是由 John Vlissides 和 Scott Stanton 编写的 Idraw 完成的。整本书的预览是由 Tim Theisen 写的 Ghostview 完成的。 Ghostview 是根据 L. Peter Deutsch 的 Ghostscript 创建的。 我还需要感谢其他的许多人,包括:Henry Baker, Kim Barrett, Ingrid Bassett, Trevor Blackwell, Paul Becker, Gary Bisbee, Frank Deutschmann, Frances Dickey, Rich 和 Scott Draves, Bill Dubuque, Dan Friedman, Jenny Graham, Alice Hartley, David Hendler, Mike Hewett, Glenn Holloway, Brad Karp, Sonya Keene, Ross Knights, Mutsumi Komuro, Steffi Kutzia, David Kuznick, Madi Lord, Julie Mallozzi, Paul McNamee, Dave Moon, Howard Mullings, Mark Nitzberg, Nancy Parmet 和其 家人, Robert Penny, Mike Plusch, Cheryl Sacks, Hazem Sayed, Shannon Spires, Lou Steinberg, Paul Stoddard, John Stone, Guy Steele, Steve Strassmann, Jim Veitch, Dave Watkins, Idelle and Julian Weber, the Weickers, Dave Yost 和 Alan Yuille。 另外,着重感谢我的父母和 Jackie。 高德纳给他的经典丛书起名为《计算机程序设计艺术》。在他的图灵奖获奖感言中,他解释 说这本书的书名源自于内心深处的潜意识 –– 潜意识告诉他,编程其实就是追求编写最优美 的程序。 就像建筑设计一样,编程既是一门工程技艺也是一门艺术。一个程序要遵循数学原理也要符 合物理定律。但是建筑师的目的不仅仅是建一个不会倒塌的建筑。更重要的是,他们要建一 个优美的建筑。 像高德纳一样,很多程序员认为编程的真正目的,不仅仅是编写出正确的程序,更重要的是 写出优美的代码。几乎所有的 Lisp 黑客也是这么想的。 Lisp 黑客精神可以用两句话来概 括:编程应该是很有趣的。程序应该很优美。这就是我在这本书中想要传达的精神。
Chapter 1 简介 (Introduction) 约翰麦卡锡和他的学生于 1958 年展开 Lisp 的初次实现工作。 Lisp 是继 FORTRAN 之后, 仍在使用的最古老的程序语言。 λ 更值得注意的是,它仍走在程序语言技术的最前面。懂 Lisp 的程序员会告诉你,有某种东西使 Lisp 与众不同。 Lisp 与众不同的部分原因是,它被设计成能够自己进化。你能用 Lisp 定义新的 Lisp 操作 符。当新的抽象概念风行时(如面向对象程序设计),我们总是发现这些新概念在 Lisp 是 最容易来实现的。Lisp 就像生物的 DNA 一样,这样的语言永远不会过时。 1.1 新的工具 (New Tools) 为什么要学 Lisp?因为它让你能做一些其它语言做不到的事情。如果你只想写一个函数来 返回小于 n 的数字总和,那么用 Lisp 和 C 是差不多的: 1 2 3 4 5 6 7 ; Lisp /* C */ (defun sum (n) int sum(int n){ (let ((s 0)) int i, s = 0; (dotimes (i n s) for(i = 0; i < n; i++) (incf s i)))) s += i; return(s); } 如果你只想做这种简单的事情,那用什么语言都不重要。假设你想写一个函数,输入一个数 n ,返回把 n 与传入参数 (argument)相加的函数。 1 2 3 4 ; Lisp (defun addn (n) #'(lambda (x) (+ x n))) 在 C 语言中 addn 怎么实现?你根本写不出来。 你可能会想,谁会想做这样的事情?程序语言教你不要做它们没有提供的事情。你得针对每 个程序語言,用其特定的思維来写程序,而且想得到你所不能描述的东西是很困难的。当我 刚开始编程时 –– 用 Baisc –– 我不知道什么是递归,因为我根本不知道有这个东西。我是 用 Basic 在思考。我只能用迭代的概念表达算法,所以我怎么会知道递归呢? 词法闭包 「Lexical Closure」 (上述 addn 的范例),相信我, Lisp 程序员 如果你没听过 一直在使用它。很难找到任何长度的 Common Lisp 程序,没有用到闭包的好处。在 112 页前,你自己会持续使用它。
闭包仅是其中一个我们在别的语言找不到的抽象概念之一。另一个更有价值的 Lisp 特点是, Lisp 程序是用 Lisp 的数据结构来表示。这表示你可以写出会写程序的程序。人们真的需 要这个吗?没错 –– 它们叫做宏,有经验的程序员也一直在使用它。学到 173 页你就可以 自己写出自己的宏了。 有了宏、闭包以及运行期类型,Lisp 凌驾在面向对象程序设计之上。如果你了解上面那句 话,也许你不应该阅读此书。你得充分了解 Lisp 才能明白为什么此言不虚。但这不是空泛 之言。这是一个重要的论点,并且在 17 章用程序相当明确的证明了这点。 第二章到第十三章会循序渐进地介绍所有你需要理解第 17 章程序的概念。你的努力会有所 回报:你会感到在 C++ 编程是窒碍难行的,就像有经验的 C++ 程序员用 Basic 编程会 感到窒息一样。更加鼓舞人心的是,如果我们思考为什么会有这种感觉。 编写 Basic 对于 平常用 C++ 编程是令人感到窒息的,是因为有经验的 C++ 程序员知道一些用 Basic 不 可能表达出来的技术。同样地,学习 Lisp 不仅教你学会一门新的语言 –– 它教你崭新的并 且更强大的程序思考方法。 1.2 新的技术 (New Techniques) 如上一节所提到的, Lisp 赋予你别的语言所没有的工具。不仅仅如此,就 Lisp 带来的新 特性来说 –– 自动内存管理 (automatic memory management),显式类型 (manifest typing),闭包 (closures)等 –– 每一项都使得编程变得如此简单。结合起来,它们组成了 一个关键的部分,使得一种新的编程方式是有可能的。 Lisp 被设计成可扩展的:让你定义自己的操作符。这是可能的,因为 Lisp 是由和你程序一 样的函数与宏所构成的。所以扩展 Lisp 就和写一个 Lisp 程序一样简单。事实上,它是如 此的容易(和有用),以至于扩展语言自身成了标准实践。当你在用 Lisp 语言編程时,你 也在创造一个适合你的程序的语言。你由下而上地,也由上而下地工作。 几乎所有的程序,都可以从订作适合自己所需的语言中受益。然而越复杂的程序,由下而上 的程序设计就显得越有价值。一个由下而上所设计出来的程序,可写成一系列的层,每层担 任上一层的程序语言。 TeX 是最早使用这种方法所写的程序之一。你可以用任何语言由下 而上地设计程序,但 Lisp 是本质上最适合这种方法的工具。 由下而上的编程方法,自然发展出可扩展的软件。如果你把由下而上的程序设计的原则,想 成你程序的最上层,那这层就成为使用者的程序语言。正因可扩展的思想深植于 Lisp 当中, 使得 Lisp 成为实现可扩展軟件的理想语言。三个 1980 年代最成功的程序提供 Lisp 作为 扩展自身的语言: GNU Emacs , Autocad ,和 Interleaf 。 由下而上的编程方法,也是得到可重用软件的最好方法。写可重用软件的本质是把共同的地 方从细节中区分出来,而由下而上的编程方法本质地创造这种区分。与其努力撰写一个庞大 的应用,不如努力创造一个语言,用相对小的努力在这语言上撰写你的应用。和应用相关的
特性集中在最上层,以下的层可以组成一个适合这种应用的语言 –– 还有什么比程序语言更 具可重用性的呢? Lisp 让你不仅编写出更复杂的程序,而且写的更快。 Lisp 程序通常很简短 –– Lisp 给了你 更高的抽象化,所以你不用写太多代码。就像 Frederick Brooks 所指出的,编程所花的时 间主要取决于程序的长度。因此仅仅根据这个单独的事实,就可以推断出用 Lisp 编程所花 的时间较少。这种效果被 Lisp 的动态特点放大了:在 Lisp 中,编辑-编译-测试循环短到使 编程像是即时的。 更高的抽象化与互动的环境,能改变各个机构开发软件的方式。术语快速建型描述了一种始 于 Lisp 的编程方法:在 Lisp 里,你可以用比写规格说明更短的时间,写一个原型出来, 而这种原型是高度抽象化的,可作为一个比用英语所写的更好的规格说明。而且 Lisp 让你 可以轻易的从原型转成产品软件。当写一个考虑到速度的 Common Lisp 程序时,通过现 代编译器的编译,Lisp 与其他的高阶语言所写的程序运行得一样快。 除非你相当熟悉 Lisp ,这个简介像是无意义的言论和冠冕堂皇的声明。Lisp 凌驾面向对象 程序设计? 你创造适合你程序的语言? Lisp 编程是即时的? 这些说法是什么意思?现在 这些说法就像是枯竭的湖泊。随着你学到更多实际的 Lisp 特色,见过更多可运行的程序, 这些说法就会被实际经验之水所充满,而有了明确的形状。 1.3 新的方法 (New Approach) 本书的目标之一是不仅是教授 Lisp 语言,而是教授一种新的编程方法,这种方法因为有了 Lisp 而有可能实现。这是一种你在未来会见得更多的方法。随着开发环境变得更强大,程 序语言变得更抽象, Lisp 的编程风格正逐渐取代旧的规划-然后-实现 (plan-and- implement)的模式。 在旧的模式中,错误永远不应该出现。事前辛苦订出缜密的规格说明,确保程序完美的运行。 理论上听起来不错。不幸地,规格说明是人写的,也是人来实现的。实际上结果是, 规划- 然后-实现 模型不太有效。 身为 OS/360 的项目经理, Frederick Brooks 非常熟悉这种传统的模式。他也非常熟悉 它的后果: 任何 OS/360 的用户很快的意识到它应该做得更好...再者,产品推迟,用了更多 的内存,成本是估计的好几倍,效能一直不好,直到第一版后的好几个版本更新, 效能才算还可以。 而这却描述了那个时代最成功系统之一。
旧模式的问题是它忽略了人的局限性。在旧模式中,你打赌规格说明不会有严重的缺失,实 现它们不过是把规格转成代码的简单事情。经验显示这实在是非常坏的赌注。打赌规格说明 是误导的,程序到处都是臭虫 (bug) 会更保险一点。 这其实就是新的编程模式所假设的。设法尽量降低错误的成本,而不是希望人们不犯错。错 误的成本是修补它所花费的时间。使用强大的语言跟好的开发环境,这种成本会大幅地降低。 编程风格可以更多地依靠探索,较少地依靠事前规划。 规划是一种必要之恶。它是评估风险的指标:越是危险,预先规划就显得更重要。强大的工 具降低了风险,也降低了规划的需求。程序的设计可以从最有用的信息来源中受益:过去实 作程序的经验。 Lisp 风格从 1960 年代一直朝着这个方向演进。你在 Lisp 中可以如此快速地写出原型,以 致于你以历经好几个设计和实现的循环,而在旧的模式当中,你可能才刚写完规格说明。你 不必担心设计的缺失,因为你将更快地发现它们。你也不用担心有那么多臭虫。当你用函数 式风格来编程,你的臭虫只有局部的影响。当你使用一种很抽象的语言,某些臭虫(如迷途 指针)不再可能发生,而剩下的臭虫很容易找出,因为你的程序更短了。当你有一个互动的 开发环境,你可以即时修补臭虫,不必经历 编辑,编译,测试的漫长过程。 Lisp 风格会这么演进是因为它产生的结果。听起来很奇怪,少的规划意味著更好的设计。 技术史上相似的例子不胜枚举。一个相似的变革发生在十五世纪的绘画圈里。在油画流行前, 画家使用一种叫做蛋彩的材料来作画。蛋彩不能被混和或涂掉。犯错的代价非常高,也使得 画家变得保守。后来随着油画颜料的出现,作画风格有了大幅地改变。油画“允许你再来一 次”这对困难主题的处理,像是画人体,提供了决定性的有利条件。 新的材料不仅使画家更容易作画了。它使新的更大胆的作画方式成为可能。 Janson 写道: 如果没有油画颜料,弗拉芒大师们的征服可见的现实的口号就会大打折扣。于是, 从技术的角度来说,也是如此,但他们当之无愧地称得上是“现代绘画之父”,油 画颜料从此以后成为画家的基本颜料。 做为一种介质,蛋彩与油画颜料一样美丽。但油画颜料的弹性给想像力更大的发挥空间── 这是决定性的因素。 程序设计正经历着相同的改变。新的介质像是“动态的面向对象语言” –– 即 Lisp 。这不是说 我们所有的软件在几年内都要用 Lisp 来写。从蛋彩到油画的转变也不是一夜完成的;油彩 一开始只在领先的艺术中心流行,而且经常混合着蛋彩来使用。我们现在似乎正处于这个阶 段。 Lisp 被大学,研究室和某些顶尖的公司所使用。同时,从 Lisp 借鉴的思想越来越多 地出现在主流语言中:交互式编程环境 (interactive programming environment)、垃 圾回收(garbage collection)、运行期类型 (run-time typing),仅举其中几个。
分享到:
收藏