人 民 第16届J o生l产t效 率奖图书 邮 了解黑窑青睐的编程语言 电 出 带{尔进λ CommLoins的 p精 彩世界 版 社 多 多人民邮电出版社 内 容 提 要 这是一本不同寻常的Common Lisp入门书。本书首先从作者的学习经过及语言历史出发,随后用21 个章节讲述了各种基础知识,主要包括:REPL及Common Lisp的各种实现、S-表达式、函数与变量、标 准宏与自定义宏、数字与字符以及字符串、集合与向量、列表处理、文件与文件I/O处理、类、FORMAT 格式、符号与包,等等。而接下来的9个章节则翔实地介绍了几个有代表性的实例,其中包含如何构建垃 圾过滤器、解析二进制文件、构建ID3解析器,以及如何编写一个完整的MP3 Web应用程序等内容。最 后还对一些未介绍内容加以延伸。 本书内容适合Common Lisp初学者及对之感兴趣的相关人士。 图灵程序设计丛书 实用Common Lisp编程 ◆ 著 [美] Peter Seibel 译 田 春 责任编辑 傅志红 ◆ 人民邮电出版社出版发行 北京市崇文区夕照寺街14号 邮编 100061 电子邮件 [email protected] 网址 http://www.ptpress.com.cn 北京 印刷 ◆ 开本:800×1000 1/16 印张:27.2519.5 字数:678千字 2011年 10 月第 1 版 印数:1 — 3 500册 2011年 10 月北京第 1 次印刷 著作权合同登记号 图字:01-2010-2360 号 ISBN 978-7-115-26374-2 定价:89.00元 读者服务热线:(010)51095186转604 印装质量热线:(010)67129223 反盗版热线:(010)67171154 XIV 目 录 目 录 第1章 绪言:为什么是Lisp........................1 4.7 宏.............................................................41 1.1 为什么是Lisp............................................2 4.8 真、假和等价..........................................42 1.2 Lisp的诞生................................................4 4.9 格式化Lisp代码.....................................43 1.3 本书面向的读者........................................6 第5章 函数....................................................46 第2章 周而复始:REPL简介.....................8 5.1 定义新函数.............................................46 2.1 选择一个Lisp实现...................................8 5.2 函数形参列表..........................................47 2.2 安装和运行Lisp in a Box........................10 5.3 可选形参.................................................48 2.3 放开思想:交互式编程...........................10 5.4 剩余形参.................................................49 2.4 体验REPL...............................................11 5.5 关键字形参.............................................50 2.5 Lisp风格的“Hello, World”.................12 5.6 混合不同的形参类型..............................51 2.6 保存工作成果..........................................13 5.7 函数返回值.............................................52 5.8 作为数据的函数——高阶函数...............53 第3章 实践:简单的数据库.......................17 5.9 匿名函数.................................................55 3.1 CD和记录...............................................17 3.2 录入CD...................................................18 第6章 变量....................................................57 3.3 查看数据库的内容..................................19 6.1 变量的基础知识......................................57 3.4 改进用户交互..........................................21 6.2 词法变量和闭包......................................60 3.5 保存和加载数据库..................................23 6.3 动态变量.................................................61 3.6 查询数据库..............................................24 6.4 常量.........................................................65 3.7 更新已有的记录——WHERE再战 6.5 赋值.........................................................65 江湖.........................................................28 6.6 广义赋值.................................................66 3.8 消除重复,获益良多..............................29 6.7 其他修改位置的方式..............................67 3.9 总结.........................................................33 第7章 宏:标准控制构造...........................69 第4章 语法和语义.......................................34 7.1 WHEN和UNLESS.....................................70 4.1 括号里都可以有什么..............................34 7.2 COND........................................................71 4.2 打开黑箱.................................................34 7.3 AND、OR和NOT.....................................72 4.3 S-表达式..................................................36 7.4 循环.........................................................72 4.4 作为Lisp形式的S-表达式.....................38 7.5 DOLIST和DOTIMES..............................73 4.5 函数调用.................................................39 7.6 DO............................................................74 4.6 特殊操作符..............................................39 7.7 强大的LOOP...........................................76 目 录 XV 第8章 如何自定义宏...................................78 11.9 序列谓词..............................................119 8.1 Mac的故事:只是一个故事...................78 11.10 序列映射函数....................................120 8.2 宏展开期和运行期..................................79 11.11 哈希表...............................................120 2 8.3 DEFMACRO...............................................80 11.12 哈希表迭代........................................122 8.4 示例宏:do-primes..............................81 第12章 LISP名字的由来:列表 3 8.5 宏形参......................................................82 处理................................................123 8.6 生成展开式..............................................83 12.1 “没有列表”.........................................123 4 8.7 堵住漏洞..................................................84 12.2 函数式编程和列表..............................126 8.8 用于编写宏的宏......................................88 12.3 “破坏性”操作.....................................127 8.9 超越简单宏..............................................90 12.4 组合回收性函数和共享结构...............129 5 第9章 实践:建立单元测试框架..............91 12.5 列表处理函数......................................131 12.6 映射.....................................................132 6 9.1 两个最初的尝试......................................91 12.7 其他结构..............................................133 9.2 重构.........................................................92 7 9.3 修复返回值..............................................94 第13章 超越列表:点对单元的其他 9.4 更好的结果输出......................................95 用法................................................134 9.5 抽象诞生..................................................97 13.1 树.........................................................134 8 9.6 测试层次体系..........................................97 13.2 集合.....................................................136 9.7 总结.........................................................99 13.3 查询表:alist和plist...........................137 9 第10章 数字、字符和字符串..................101 13.4 DESTRUCTURING-BIND.....................141 10 10.1 数字.....................................................101 第14章 文件和文件I/O............................143 10.2 字面数值..............................................102 14.1 读取文件数据......................................143 10.3 初等数学..............................................104 14.2 读取二进制数据..................................145 11 10.4 数值比较..............................................106 14.3 批量读取..............................................145 10.5 高等数学..............................................107 14.4 文件输出..............................................145 12 10.6 字符.....................................................107 14.5 关闭文件..............................................146 10.7 字符比较..............................................107 14.6 文件名.................................................147 13 10.8 字符串..................................................108 14.7 路径名如何表示文件名.......................149 10.9 字符串比较..........................................109 14.8 构造新路径名......................................150 14 14.9 目录名的两种表示方法.......................152 第11章 集合................................................111 14.10 与文件系统交互................................153 11.1 向量.....................................................111 14.11 其他I/O类型.....................................154 15 11.2 向量的子类型......................................113 11.3 作为序列的向量..................................114 第15章 实践:可移植路径名库..............157 16 11.4 序列迭代函数......................................114 15.1 API.......................................................157 11.5 高阶函数变体......................................116 15.2 *FEATURES*和读取期条件化............157 11.6 整个序列上的操作...............................117 15.3 列目录.................................................159 17 11.7 排序与合并..........................................118 15.4 测试文件的存在..................................162 11.8 子序列操作..........................................118 15.5 遍历目录树..........................................164 18 XVI 目 录 第16章 重新审视面向对象:广义 19.3 状况处理器..........................................205 函数................................................165 19.4 再启动.................................................207 16.1 广义函数和类......................................166 19.5 提供多个再启动..................................210 16.2 广义函数和方法..................................167 19.6 状况的其他用法..................................211 16.3 DEFGENERIC.......................................168 第20章 特殊操作符...................................213 16.4 DEFMETHOD.........................................169 20.1 控制求值.............................................213 16.5 方法组合..............................................171 20.2 维护词法环境......................................213 16.6 标准方法组合......................................172 20.3 局部控制流..........................................216 16.7 其他方法组合......................................173 20.4 从栈上回退..........................................219 16.8 多重方法..............................................174 20.5 多值.....................................................223 16.9 未完待续……......................................176 20.6 EVAL-WHEN.........................................224 第17章 重新审视面向对象:类..............177 20.7 其他特殊操作符..................................227 17.1 DEFCLASS...........................................177 第21章 编写大型程序:包和符号.........228 17.2 槽描述符..............................................178 21.1 读取器是如何使用包的......................228 17.3 对象初始化..........................................179 21.2 包和符号相关的术语..........................230 17.4 访问函数..............................................182 21.3 三个标准包..........................................230 17.5 WITH-SLOTS和WITH- 21.4 定义你自己的包..................................232 ACCESSORS.........................................185 21.5 打包可重用的库..................................234 17.6 分配在类上的槽..................................186 21.6 导入单独的名字..................................235 17.7 槽和继承..............................................187 21.7 打包技巧.............................................236 17.8 多重继承..............................................188 21.8 包的各种疑难杂症..............................237 17.9 好的面向对象设计..............................190 第22章 高阶LOOP...................................240 第18章 一些FORMAT秘诀....................191 22.1 LOOP的组成部分................................240 18.1 FORMAT函数.......................................192 22.2 迭代控制.............................................241 18.2 FORMAT指令.......................................193 22.3 计数型循环..........................................241 18.3 基本格式化..........................................194 22.4 循环集合和包......................................242 18.4 字符和整数指令..................................194 22.5 等价然后迭代....................................243 18.5 浮点指令..............................................196 22.6 局部变量.............................................244 18.6 英语指令..............................................197 22.7 解构变量.............................................245 18.7 条件格式化..........................................198 22.8 值汇聚.................................................245 18.8 迭代.....................................................199 22.9 无条件执行..........................................247 18.9 跳,跳,跳..........................................201 22.10 条件执行...........................................247 18.10 还有更多……....................................202 22.11 设置和拆除........................................248 22.12 终止测试...........................................250 第19章 超越异常处理:状况和 22.13 小结...................................................251 再启动............................................203 19.1 Lisp的处理方式..................................204 第23章 实践:垃圾邮件过滤器..............252 19.2 状况.....................................................205 23.1 垃圾邮件过滤器的核心......................252 目 录 XVII 23.2 训练过滤器..........................................255 第26章 实践:用AllegroServe进行 23.3 按单词来统计......................................257 Web编程......................................315 23.4 合并概率..............................................259 26.1 30秒介绍服务器端Web编程.............315 2 23.5 反向卡方分布函数...............................261 26.2 AllegroServe........................................317 23.6 训练过滤器..........................................262 26.3 用AllegroServe生成动态内容............320 3 23.7 测试过滤器..........................................263 26.4 生成HTML.........................................321 23.8 一组工具函数......................................265 26.5 HTML宏.............................................324 23.9 分析结果..............................................266 26.6 查询参数..............................................325 4 23.10 接下来的工作....................................268 26.7 cookie..................................................327 第24章 实践:解析二进制文件..............269 26.8 小型应用框架......................................329 5 26.9 上述框架的实现..................................330 24.1 二进制文件..........................................269 24.2 二进制格式基础..................................270 第27章 实践:MP3数据库.....................334 6 24.3 二进制文件中的字符串.......................271 27.1 数据库.................................................334 24.4 复合结构..............................................273 27.2 定义模式..............................................336 7 24.5 设计宏..................................................274 27.3 插入值.................................................338 24.6 把梦想变成现实..................................275 27.4 查询数据库..........................................340 8 24.7 读取二进制对象..................................277 27.5 匹配函数..............................................342 24.8 写二进制对象......................................279 27.6 获取结果..............................................344 9 24.9 添加继承和标记的结构.......................280 27.7 其他数据库操作..................................346 24.10 跟踪继承的槽....................................281 第28章 实践:Shoutcast服务器...........348 10 24.11 带有标记的结构................................284 24.12 基本二进制类型................................285 28.1 Shoutcast协议.....................................348 24.13 当前对象栈........................................288 28.2 歌曲源.................................................349 11 28.3 实现Shoutcast.....................................351 第25章 实践:ID3解析器.......................290 第29章 实践:MP3浏览器.....................357 12 25.1 ID3v2标签的结构...............................291 29.1 播放列表..............................................357 25.2 定义包..................................................292 29.2 作为歌曲源的播放列表.......................359 13 25.3 整数类型..............................................292 29.3 操作播放列表......................................362 25.4 字符串类型..........................................294 29.4 查询参数类型......................................365 25.5 ID3标签头...........................................297 14 29.5 样板HTML.........................................367 25.6 ID3帧..................................................298 29.6 浏览页.................................................368 25.7 检测标签补白......................................300 15 29.7 播放列表..............................................371 25.8 支持ID3的多个版本...........................301 29.8 查找播放列表......................................373 25.9 版本化的帧基础类...............................303 29.9 运行应用程序......................................374 16 25.10 版本化的具体帧类.............................304 25.11 你实际需要哪些帧.............................305 第30章 实践:HTML生成库,解释器 25.12 文本信息帧........................................307 部分................................................375 17 25.13 评论帧................................................309 30.1 设计一个领域相关语言.......................375 25.14 从ID3标签中解出信息.....................310 30.2 FOO语言.............................................376 18 XVIII 目 录 30.3 字符转义..............................................379 31.3 FOO宏................................................399 30.4 缩进打印器..........................................380 31.4 公共API..............................................401 30.5 HTML处理器接口..............................381 31.5 结束语.................................................403 30.6 美化打印器后台..................................382 第32章 结论:下一步是什么..................404 30.7 基本求值规则......................................385 30.8 下一步是什么......................................389 32.1 查找Lisp库........................................404 32.2 与其他语言接口..................................406 第31章 实践:HTML生成库,编译器 32.3 让它工作,让它正确,让它更快.......406 部分................................................390 32.4 交付应用程序......................................413 31.1 编译器.................................................390 32.5 何去何从.............................................415 31.2 FOO特殊操作符.................................395 《Practical Common Lisp》- 序言部分 书评,作者和序言等 对《 》的评价(封面) Practical Common Lisp “Peter Seibel的《Practical Common Lisp》名副其实:对那些想要学习并开始将Common Lisp 用于实际工作的人来说是一本极佳的介绍性教材。这本书写得非常好并且读起来很有趣— —至少对于那些认为学习新语言很有趣的人来说是这样的。 “与其花大量时间来抽象地讨论Lisp在编程语言界的地位,Seibel选择了正确的切入点, 通过一系列复杂度递增的编程示例来引导读者。这一思路把重点放在了那些有经验的程序员们最 常使用的Common Lisp特性上,而没有纠缠于那些即便专家也要查询手册才知道的Common Lisp 语言特性的角落。Seibel 这一示例驱动的思路的结果就是让读者准确地感受到了 Common Lisp 在以最少的努力构建复杂和革命性的软件系统过程中所体验出的强大威力。 “在Common Lisp领域已经有许多好的书籍采用了更为抽象和比较性的编写思路,但一本‘这 就是你怎样完成它——以及为什么要这样做’风格的好书绝对是有价值的贡献,无论对当前的 Common Lisp用户和其他潜在的用户来说都是这样。” ——Scott E. Fahlman,Carnegie Mellon大学计算机科学研究教授 “要是这本书在我当初最开始学 Lisp 的时候已经存在就好了。并不是说当时没有其他关于 Common Lisp的好书了,但它们都不像这本书那样具有务实和与时俱进的思想。并且让我们不要 忘了Peter涵盖了诸如路径名、状况和再启动等主题,这些内容在其他Lisp著作里完全被忽略 掉了。 “如果你初学 Lisp 并且想要选择一个正确的切入点,那么就不要犹豫赶快买下这本书吧。 一旦你阅读并学会了它,然后接下来你就可以继续阅读Graham、Norvig、Keene和Steele等人 的‘经典’著作了。” ——Edi Weitz,《Common Lisp Cookbook》的维护者和CL-PPCRE正则表达式库的作者。 “有经验的程序员可以从示例中学到最有用的知识,而Lisp最终被用在Seibel这本示例丰 富的入门教材中是件令人高兴的事。而尤其令人高兴的是,这本书包含了如此多的涵盖当今程序 员日常可能用到的诸多问题领域,诸如Web开发和流媒体技术。” ——Philip Greenspun,《Software Engineering for Internet Applications》的作者, MIT电子工程和计算机科学学院 1 / 6