实用Common Lisp编程

This document was uploaded by one of our users. The uploader already confirmed that they had the permission to publish it. If you are author/publisher or own the copyright of this documents, please report to us by using this DMCA report form.

Simply click on the Download Book button.

Yes, Book downloads on Ebookily are 100% Free.

Sometimes the book is free on Amazon As well, so go ahead and hit "Search on Amazon"

由塞贝尔编著的《实用Common Lisp编程》是一本不同寻常的Common Lisp入门书。《实用Common Lisp编程》首先从作者的学习经过及语言历史出发,随后用21个章节讲述了各种基础知识,主要包括:REPL及Common Lisp的各种实现、S-表达式、函数与变量、标准宏与自定义宏、数字与字符以及字符串、集合与向量、列表处理、文件与文件I/O处理、类、FORMAT格式、符号与包,等等。而接下来的9个章节则翔实地介绍了几个有代表性的实例,其中包含如何构建垃圾过滤器、解析二进制文件、构建ID3解析器,以及如何编写一个完整的MP3 Web应用程序等内容。最后还对一些未介绍内容加以延伸。

《实用Common Lisp编程》内容适合Common Lisp初学者及对之感兴趣的相关人士。

2021/10/31 modified version.

Author(s): Peter Seibel;田春(译)
Series: 图灵程序设计丛书
Publisher: 人民邮电出版社
Year: 2011

Language: Chinese
Pages: 417

目录
Practical Common Lisp
第1章 绪言:为什么是Lisp?
1.1 为什么是Lisp?
1.2 Lisp的诞生
1.3 本书面向的读者
第2章 周而复始: REPL简介
2.1 选择一个Lisp实现
2.2 安装和运行Lisp in a Box
2.3 放开思想:交互式编程
2.4 体验REPL
2.5 Lisp风格的“Hello, World”
2.6 保存你的工作
调试一个运行在一亿英里之外且价值一亿美元硬件上的程序是件有趣的经历。拥有一个运行在宇宙飞船上的读-求值-打印循环,在查找和修复这个问题的过程中,被证明是无价的。
第3章 实践:一个简单的数据库
3.1 CD和记录
3.2 录入CD
3.3 查看数据库的内容
3.4 改进用户交互
3.5 保存和加载数据库
3.6 查询数据库
3.7 更新已有的记录——WHERE的再次使用
3.8 消除重复,获益良多
3.9 总结
第4章 语法和语义
4.1 括号里都可以有什么?
这个精确定义M-表达式以及将其编译或至少转译成S-表达式的工程,既没有完成也没有明确放弃,它只不过是被推迟到无限遥远的未来罢了。新一代的[相比S-表达式]更加偏爱类FORTRAN或类Algol表示法的程序员也许会最终实现它。
4.2 打开黑箱
4.3 S-表达式
4.4 作为Lisp形式的S-表达式
4.5 函数调用
4.6 特殊操作符
4.7 宏
4.8 真、假和等价
4.9 格式化Lisp代码
第5章 函数
5.1 定义新函数
5.2 函数形参列表
5.3 可选形参
5.4 剩余形参
5.5 关键字形参
5.6 混合不同的形参类型
5.7 函数返回值
5.8 作为数据的函数——高阶函数
5.9 匿名函数
第6章 变量
6.1 变量基础
6.2 词法变量和闭包
6.3 动态(特殊)变量
6.4 常量
6.5 赋值
6.6 广义赋值
6.7 其他修改位置的方式
第7章 宏:标准控制构造
7.1 WHEN和UNLESS
7.2 COND
7.3 AND,OR和NOT
7.4 循环
7.5 DOLIST和DOTIMES
7.6 DO
7.7 强大的LOOP
第8章 定义你自己的宏
8.1 Mac的故事:只是一个故事
8.2 宏展开期和运行期
8.3 DEFMACRO
8.4 一个示例宏:do-primes
8.5 宏参数
8.6 生成展开式
8.7 堵上漏洞
8.8 用于编写宏的宏
另一个经典的用于编写宏的宏:ONCE-ONLY
8.9 超越简单宏
第9章 实践:建立一个单元测试框架
9.1 两个最初的尝试
9.2 重构
9.3 修复返回值
9.4 更好的结果输出
9.5 抽象诞生
9.6 测试层次体系
9.7 总结
第10章 数字、字符和字符串
10.1 数字
10.2 字面数值
10.3 初等数学
10.4 数值比较
10.5 高等数学
10.6 字符
10.7 字符比较
10.8 字符串
10.9 字符串比较
第11章 集合
11.1 向量
11.2 向量的子类型
11.3 作为序列的向量
11.4 序列迭代函数
11.5 高阶函数变体
11.6 整个序列的管理
11.7 排序与合并
11.8 子序列管理
11.9 序列谓词
11.10 序列映射函数
11.11 哈希表
11.12 哈希表迭代
第12章 LISP名字的由来:列表处理
12.1 “没有列表”
12.2 函数式编程和列表
12.3 “破坏性”操作
12.4 组合回收性函数和共享结构
12.5 列表处理函数
12.6 映射
12.7 其他结构
第13章 超越列表:点对单元的其他用法
13.1 树
13.2 集合
13.3 查询表:alist和plist
13.4 DESTRUCTURING-BIND
第14章 文件和文件I/O
14.1 读写文件数据
14.2 读取二进制数据
14.3 批量读取
14.4 文件输出
14.5 关闭文件
14.6 文件名
存在于上世纪70和80年代的文件系统的历史多样性很容易被遗忘。Kent Pitman,Common Lisp标准的主要技术编辑之一,有一次在comp.lang.lisp (Message-ID: [email protected])描述了如下的情形:
在Common Lisp的设计完成时期处于支配地位的文件系统是:TOPS-10、TENEX、TOPS-20、VAX VMS、AT&T Unix、MIT Multics、MIT ITS,更不用说还有许多大型机操作系统。它们中的一些只支持大写字母,一些是大小写混合的,另一些是大小写敏感的但却自动做大小写转换(就像Common Lisp)。它们中的一些将目录视为文件,另一些则不会。一些对于特殊的文件字符带有引用字符,另一些不会。一些带有通配符,而另一些没有。一些在相对路径名中使用:up,另一些不这样做。...
如果你从任何单一文件系统的观点上观察路径名抽象,那么它看起来显得过于复杂。不过,如果你考察两种像Windows和Unix这样相似的文件系统,你可能已经开始注意到路径名系统可能帮你抽象掉的一些区别了──例如,Windows文件名含有一个驱动器字母,而Unix文件名却没有。使用这种被涉及用来处理过去存在的广泛的文件系统的路径名抽象所带来的另一种好处是,它有可能可以处理将来可能存在的文件系统。比如说如果版本文件系统重新流行起来的话,Common Lisp就已经准备好了。
14.7 路径名如何表示文件名
14.8 构造新路径名
14.9 目录名的两种表示方法
14.10 与文件系统交互
14.11 其他I/O类型
第15章 实践:一个可移植路径名库
15.1 API
15.2 *FEATURES*和读取期条件化
从包的角度来说,如果你下载了该库的完整代码,你将看到它被定义在一个新的包中,com.gigamonkeys.pathnames。我将在第21章里讨论定义使用包的细节。目前你应当注意某些实现提供了它们自己的包,其中含有一些函数与你将在本章中定义的一些函数带有相同的名字,并且这些名字可在CL-USER包中访问。这样,如果你试图在CL-USER包中定义该库中的某些函数,将可能会得到关于破坏了已有定义的错误或警告。为了避免这种可能性,你可以创建一个称为packages.lisp的文件,其中带有下面的内容:
并加载它。然后在REPL中或者在你输入来自本章的定义的文件顶端,输入下列表达式:
将库以这种形式打包,除了可以避免与那些已存在于CL-USER包中的符号产生冲突以外,还可以使其更容易被其他代码所使用,你在未来几章中将会看到这一点。
15.3 列目录
15.4 测试一个文件的存在
15.5 遍历一个目录树
第16章 重新审视面向对象:广义函数
16.1 广义函数和类
16.2 广义函数和方法
16.3 DEFGENERIC
16.4 DEFMETHOD
16.5 方法组合
16.6 标准方法组合
16.7 其他方法组合
16.8 多重方法
曾经使用过诸如Java和C++这些静态类型消息传递语言的程序员们可能认为多重方法听起来类似于这些语言中一种称为方法重载(method overloading)的特性。不过这两种语言特性事实上相当不同,因为重载的方法是在编译期被选择的,其所基于的是编译期的参数类型而不是运行期。为了看到方法重载的工作方式,考虑下面的两个Java类:
现在考虑当你从下面的类中运行24Tmain24T方法时将会发生什么。
当你告诉Main来实例化A时,它像你可能期待的那样打印出“A/A”。
不过,如果你告诉Main来实例化一个B,那么obj的真正类型将只有一半被实际分发。
如果重载的方法像Common Lisp的多重方法那样工作,那么上面将代替打印出“B/B”。在消息传递语言里有可能手工实现多重分发,但这将与消息传递模型背道而驰,因为一个多重分发的方法中的代码并不属于任何一个类。
16.9 未完待续……
第17章 重新审视面向对象:类
17.1 DEFCLASS
术语“用户定义的类”不是来自语言标准的术语──从技术上来讲,当我说“用户定义的类”时我指的是那些属于24TSTANDARD-OBJECT24T的子类并且其元类(metaclass)是24TSTANDARD-CLASS24T的类。但由于我不打算谈论你可以定义不是24TSTANDARD-OBJECT24T的子类并且其元类不是24TSTANDARD-CLASS24T的那些类的方式,因此你根本不需要关心这点。“用户定义的”并不是一个用来描述这些类的完美术语,因为实现可能以相同的方式定义了特定的类。不过,将...
17.2 槽描述符
17.3 对象初始化
17.4 访问函数
17.5 WITH-SLOTS和WITH-ACCESSORS
17.6 分配在类上的槽
17.7 槽和继承
17.8 多重继承
17.9 好的面向对象设计
第18章 一些FORMAT秘决
18.1 FORMAT函数
18.2 FORMAT指令
18.3 基本格式化
18.4 字符和整数指令
18.5 浮点指令
18.6 英语指令
18.7 条件格式化
18.8 迭代
18.9 跳,跳,跳
18.10 还有更多……
第19章 超越异常处理:状况和再启动
19.1 Lisp的处理方式
19.2 状况
19.3 状况处理器
24THANDLER-CASE24T是与Java或Python风格的异常处理最接近的Common Lisp相似物。你在Java中可能写成这样:
或是Python写成这样:
而在Common Lisp中你需要写成这样:
19.4 再启动
19.5 提供多个再启动
19.6 状况的其他用法
对于编写健壮的软件方面的信息,你可以从查找一本Glenford J.Meyers编写的叫做《Software Reliability》(John Wiley & Sons,1976)的书开始。Bertrand Meyer关于Design By Contract的著作也提供了一种思考软件正确性的有用方式。例如,参见他的《Object-Oriented Software Construction》(Prentice Hall,1997)一书的第11和12章。不过要记住,Bertrand Meyer是E...
第20章 特殊操作符
20.1 控制求值
20.2 维护词法环境
20.3 局部控制流
20.4 从栈上回退
20.5 多值
20.6 EVAL-WHEN
20.7 其他特殊操作符
第21章 编写大型程序:符号和包
21.1 读取器是如何使用包的
21.2 包和符号的词汇表
21.3 三个标准包
21.4 定义你自己的包
21.5 打包可重用的库
21.6 导入单独的名字
21.7 打包技巧
21.8 包的各种疑难杂症
第22章 高阶LOOP
22.1 LOOP的组成部分
22.2 迭代控制
22.3 计数型循环
22.4 在集合和包上循环
22.5 等价-然后(equals-then)迭代
22.6 局部变量
22.7 解构变量
22.8 值汇聚
22.9 无条件执行
22.10 条件执行
22.11 设置和拆除
22.12 终止测试
22.13 把所有东西放在一起
第23章 实践:一个垃圾过滤器
23.1 垃圾过滤器的心脏
23.2 训练过滤器
23.3 每单词的统计
23.4 合并概率
23.5 反向卡方分布函数
23.6 训练过滤器
23.7 测试过滤器
23.8 一组工具函数
23.9 分析结果
23.10 接下来的工作
第24章 实践:解析二进制文件
24.1 二进制文件
24.2 二进制格式基础
24.3 二进制文件中的字符串
24.4 复合结构
24.5 设计宏
24.6 把梦想变成现实
24.7 读取二进制对象
24.8 写二进制对象
24.9 添加继承和标记的结构
24.10 跟踪继承的槽
24.11 带有标记的结构
24.12 基本二进制类型
24.13 当前对象栈
第25章 实践:一个ID3解析器
25.1 一个ID3v2标签的结构
25.2 定义一个包
25.3 整数类型
25.4 字符串类型
25.5 ID3标签头
25.6 ID3帧
25.7 检测标签补白
25.8 支持ID3的多个版本
25.9 版本化的帧基础类
25.10 版本化的具体帧类
25.11 你实际需要哪些帧?
25.12 文本信息帧
25.13 评论帧
25.14 从ID3标签中解出信息
第26章 实践:使用AllegroServe进行Web编程
26.1 30秒介绍服务端Web编程
26.2 AllegroServe
26.3 用AllegroServe生成动态内容
26.4 生成HTML
26.5 HTML宏
26.6 查询参数
26.7 Cookie
26.8 一个小型应用框架
26.9 实现
第27章 实践:一个MP3数据库
27.1 数据库
用于你将在本章中开发的代码的包如下所示:
其中的24T:use24T部分可以让你访问那些从第14、8和25章所定义的包中导出名字所对应的函数和宏,而24T:export24T部分导出了该库将要提供的API,你将在第29章里用到它们。
27.2 定义一个模式
27.3 插入值
27.4 查询数据库
27.5 匹配函数
27.6 获取结果
27.7 其他数据库操作
第28章 Shoutcast服务器
28.1 Shoutcast协议
28.2 歌曲源
用于你将在本章里开发的代码的包如下所示:
28.3 实现Shoutcast
第29章 一个MP3浏览器
29.1 播放列表
你可以使用下列DEFPACKAGE来定义用于本章中代码的包:
由于这是一个高阶应用,因此它用到了许多底层包。它还从ACL-SOCKET包中导入了三个符号,并从MULTIPROCESSING包中导入了其余两个,这是因为它只需要这两个包中导出的5个符号而不需要其他的139个符号。
29.2 作为歌曲源的播放列表
29.3 操作播放列表
29.4 查询参数类型
29.5 样板HTML
29.6 浏览页
29.7 播放列表
29.8 查找播放列表
29.9 运行应用程序
第30章 实践:一个HTML生成库,解释器部分
30.1 设计一个领域相关语言
30.2 FOO语言
30.3 字符转义
由于FOO是一个底层库,因此你所开发的这个包并不依赖很多外部代码——只有通常依赖的来自26TCOMMON-LISP26T包的名字以及几乎同样经常依赖的来自26TCOM.GIGAMONKEYS.MACRO-UTILITIES26T的宏生成宏的名字。另一方面,该包需要导出所有被使用FOO的代码所需要的名字。下面是来自可从本书Web站点上下载的源代码中的26TDEFPACKAGE26T定义:
30.4 缩进打印器
30.5 HTML处理器接口
30.6 美化打印器后台
一个替代的方法将是使用EVAL来求值解释器中的Lisp表达式。这种方法的问题在于EVAL无法访问词法环境。因此,没有办法让类似下面的代码正常工作:
其中26Tx26T是一个词法变量。在运行期传递给26Temit-html26T的符号x与同名的词法变量没有特别的关联。Lisp编译器将代码中对x的引用指向该变量,但在代码被编译以后,名字x和该变量之间就不再有必要的关联的。这就是当你认为26TEVAL26T是一个对你问题的解决方案时,你可能犯错误的主要原因。
不过,如果26Tx26T是一个以26TDEFVAR26T或26TDEFPARAMETER26T声明的动态变量(从而可能会被命名为26T*x*26T以代替26Tx26T),那么26TEVAL26T就可以得到它的值。这样,允许FOO解释器在某些情况下使用26TEVAL26T将是有用的。但总是使用26TEVAL26T显然不是个好主意。所以你可以将26TEVAL26T跟状况系统一起使用,将两种思想组合在一起从而同时得到两者的优点。
首先定义当26Tembed-value26T和26Tembed-code26T在解释器中调用时你将抛出的一些错误类。
现在你可以实现26Tembed-value26T和26Tembed-code26T来抛出这些错误并提供一个将使用26TEVAL26T来求值形式的再启动。
现在你可以做类似下面的事情:
然后你将以下列信息进入调试器:
如果你调用26Tevaluate26T再启动,那么26Tembed-value26T将26TEVAL26T 26T*x*26T,得到值10,然后生成下面的HTML:
然后,出于方便的考虑你可以在特定的情形下提供再启动函数——可以调用26Tevaluate26T再启动的函数。26Tevaluate26T再启动函数无条件地调用同名的再启动,而26Teval-dynamic-variables26T和26Teval-code26T仅当其状况中的形式是一个动态变量或潜在的代码时才调用再启动。
现在你使用26THANDLER-BIND26T来设置一个处理器,自动地为你调用26Tevaluate26T再启动。
最后,你可以定义一个宏来提供绑定两种类型错误的处理器的一个漂亮的语法。
一旦定义了这个宏,你就可以写出下面的代码:
30.7 基本求值规则
30.8 下一步是什么?
第31章 实践:一个HTML生成库,编译器部分
31.1 编译器
31.2 FOO特殊操作符
31.3 FOO宏
31.4 公共API
31.5 结束语
第32章 结论:下一步是什么?
32.1 查找Lisp库
32.2 与其他语言接口
32.3 让它工作,让它正确,让它更快
32.4 分发应用程序
32.5 何去何从
书评,作者和序言等
对《Practical Common Lisp》的评价(封面)
对《Practical Common Lisp》的评价
关于作者
关于技术审稿人
致谢
排版约定
书评(封底)
作者注(封底)