基本信息
- 原书名:Higher-Order Perl: Transforming Programs with Programs
- 原出版社: Morgan Kaufmann

【插图】

编辑推荐
Perl全球社区公认经典著作,资深Perl专家(核心贡献者之一)数十年工作经验结晶,Perl6设计者之一Conway亲自作序推荐
深入探讨Perl领域的各种经典问题和新主题,包含大量最佳实践和真知灼见,Perl程序员进阶必读
内容简介
计算机书籍
《高阶Perl》是Perl全球社区公认的经典著作,是资深Perl技术专家(核心贡献者之一)数十年工作经验的结晶,Perl 6设计者之一Conway亲自作序推荐。本书处处皆珍宝,不仅对Perl领域的各种经典问题给出了独到且精辟的解释,而且深入探讨了Perl中各种最新的主题,如递归、迭代器、过滤器、记忆术、划分、数值方法、高阶函数、currying、切断排序、基于语法的解析、惰性求值和约束编程等内容,并将这些转换成现实编程工作中强有力的实用工具:文件系统互动、HTML处理、数据库访问、网页抓取、排版、邮件处理、家庭理财、文本描图和图表生成等。全书包含大量真知灼见和最佳实践。
全书共9章:第1章介绍了递归与调用等参数化函数行为,分析了数制之间的转换、目录遍历、递归适用条件等;第2章讲解了代码引用的另一种用法—分配表;第3章介绍了解决性能问题的一个简单和普遍的做法—缓存;第4章讲解了迭代器的详细使用方式,包括迭代器概念、自制迭代器、迭代器实例、过滤与变换、半谓词问题、网页抓取等;第5章讲解了将通用递归函数转换到迭代器的技术;第6章介绍了如何使用无限流来摒弃迭代器的缺陷,涉及链表、递归流、正则字符串等内容;第7章介绍了把一个普通的函数转换成一个函数工厂以制造更多函数的currying技术,以及把一个函数转换成另一个函数的技术;第8章讲解了将未结构化的输入转换为数据结构的方式—解析;第9章介绍了声明式编程的技术与应用。
作译者
膝家海Perl技术实践者,精通Peri应用开发.对Perl技术拥有独到的认识和理解,近十年来一直参与Perl的实践开发,拥有丰富经验。业余时间潜心于技术的钻研,热衷于分享Perl技术,目前供职于一家IC没计公司,任CAD主管。
目录
本书赞誉
译者序
前言
第1章 递归与回调 1
1.1 十进制到二进制的转换 1
1.2 阶乘 2
1.2.1 为什么私有变量是重要的 3
1.3 汉诺塔 4
1.4 层次化数据 8
1.5 目录遍历的应用和变化 11
1.6 函数式编程与面向对象式编程 17
1.7 HTML 17
1.7.1 更灵活的选择 21
1.8 当递归膨胀时 22
1.8.1 Fibonacci数 22
1.8.2 划分 24
第2章 分配表 27
2.1 配置文件处理 27
2.1.1 表驱动配置 28
译者序
几年前我第一次读到本书时,完全被它震撼,原来Perl可以这么优雅与强大。后来一边读一边默默祈祷能有中译本。直到去年年初,我苦苦等待的还是没有到来,于是我萌发了一个大胆的念头:何不自己试试?在草稿翻译过半以后,我就电话联系了华章公司……现在你就看到中译本了。
此中译本是依照原书第2次印刷版所翻译的,所有的勘误已经订正。翻译的过程是很愉快的,因为这是我非常喜欢的书。为了它,我把很久不用的几本词典都放在了手边;为了它,我学会了LATEX;为了它,我戒掉了周末睡懒觉的坏习惯。所有付出的回报就是很高兴能与大家分享这本好书。尽管付出了最大的努力,但是一定还有一些不足之处,敬请批评指正。
网站
承蒙作者的美意,中译本的勘误和索引等内容也放在他的网站上:
http://perl.plover.com/hop/chinese.html
原书的代码示例由边注标明,在中译本中改成了在代码前增加一行“### Code Library: some-example”,代码依旧可以从如下地址下载:
http://perl.plover.com/hop/Examples/some-example
如果对本书有任何意见或建议,请发邮件给我:jhteng@gmail.com。
致谢
这本书的出版得到了许多人的帮助与支持,没有他们的辛勤付出,这本书是不可能完成的。
首先感谢机械工业出版社华章公司的诸位编辑。感谢姚蕾女士的信任,在我推荐之后认真地了解了此书并积极与原出版社联系,这才促成了此中译本的出版。还要感谢杨福川先生和秦健先生,他们经常积极回复我的电话和邮件,并耐心细致地解答和帮助,秦健先生还在审阅过程中指出了此书的许多错误,给予了许多宝贵的意见。还要感谢在幕后辛勤付出的排版、校对、封面设计等编辑,本书的完成不能缺少他们的付出。如果你看到某些句子明显比其他句子更通顺合理,那是出版社各位编辑的功劳,如果您看到一些聱牙的句子,那全都是我的责任。
其次要感谢李剑先生。他在网络上分享了前三章译稿,这也是作者向我推荐的。我在翻译结束后参考了李剑先生的译作,并纠正了此书中的几处错误。
还要感谢我的家人,在他们的理解与支持之下,近一年以来我把几乎所有的业余时间都投入了翻译之中。
最后要感谢作者Mark Jason Dominus(陶敏修)先生,他不仅耐心细致地解答我全部的疑问,主动给予我一些对翻译有帮助的资料,还很有兴趣地指出了几个可能译错的地方,居然还真有一个被说中(你猜猜是哪句?)。总之,与他的沟通是愉快的且获益匪浅。要是没有他热忱的帮助,我是不可能完成此书的。Thank you, Dominus!
滕家海
前言
怎么会这样呢?Perl的设计初衷是一方面作为C的替代品,另一方面作为UNIX脚本语言(如Bourne Shell和awk)的替代品。Perl最初的主要拥护者是UNIX系统管理员,他们熟悉C和UNIX脚本语言,因此自然地倾向把Perl程序写成类似于C和awk的程序。Perl的发明人(Larry Wall)来自这个系统管理员社区,还有Randal Schwartz,与Perl合著了《Programming Perl》,本书是第一本也仍然是最重要的一本Perl参考著作。其他重要的早期贡献者还包括Tom Christiansen,也是古董级C与Unix专家。即使Perl程序员不是来自Unix系统管理员社区,他们也被其中的人或者其中的人训练的人训练成那样。
大约在1993年我开始阅读关于Lisp 的书,我有一个重要的发现:Perl更像Lisp而不是C。如果你拿起一本优秀的Lisp书,其中会有一段文字描述Lisp的优秀特点。例如,《Paradigms of Artificial Intelligence Programming》,作者Peter Norvig,有一节标题是“是什么让Lisp与众不同”,其中就描述了Lisp的七个特点。Perl分享了其中六个,C一个也没有分享。这些是巨大的、重要的特点,如头等函数、符号表的动态访问以及自动存储管理。Lisp程序员自1957年以来就在使用这些特点。他们知道如何高效使用这些语言特点的许多方法。如果Perl程序员能发现这些Lisp程序员已经知道的事情,那么他们将学到许多使Perl编程工作更轻松的方法。
说比做容易。几乎没有人愿意听Lisp程序员的。Perl人对Lisp心存芥蒂,就像Larry Wall 的著名评论所表明的,Lisp与混合了剪下的指甲碎屑的燕麦看起来一样。Lisp程序员经常制造像“cons”与“cooder”的滑稽噪声,他们还讨论像PC loser-ing问题的东西。他们相信Lisp比其他语言更好,他们也是这么说的,这让人不快。但是现在一切都好了,因为现在你不必听Lisp人的了。你可以听我的。我将制造一些轻缓的关于散列和存储以及glob的噪声,并讨论流行的和令人鼓舞的软引用与变量销毁问题。与其告诉你Lisp有多么好,不如告诉你Perl有多么好,到最后你将不会对Lisp有任何认识,但是对Perl知道得将会更多。
然后你可以停止用Perl写C程序了。我认为你将发现这是一个很好的改变。Perl就是Perl的样子,比一个慢版本的C好得多。当你写Perl程序而不是C程序时,你将惊喜于所能够做到的。
网站
本书中的所有代码示例可以从如下网站获得:
http://perl.plover.com/hop/
当代码段中标示某某例子的标签时,那段代码就可以从如下网址下载:
http://perl.plover.com/hop/Examples/some-example
该网站还包括完整的文本、一个勘误表,以及其他有趣的内容。针对本书有任何问题都可以给我发电子邮件,请发邮件至mjd-hop@plover.com。
致谢
每段致谢都以这样一句开头“要是没有我的编辑Tim Cox不知疲倦的支持与协助,这本书肯定还没写完”。除非你写一本书,不然你将不会意识到这是多么真实的。在这里我无法用语言表达,要是没有Tim不知疲倦的支持与协助,这本书就不会写完,感谢他的贡献、友善,还有他极大的耐心。
这本书姗姗来迟,在我工作的时候Tim经历了三位助理。所有这些人都是乐于助人的和能干的,因此我谢谢Brenda Modliszewksi、Stacie Pierce以及Richard Camp。“能干的”听起来可能无力,但是我认为这是最高的褒奖。
多谢产品经理Troy Lilly与Simon Crump,不仅是能干的而且与他们合作愉快。
临近成书之前,我开始为实例代码写测试。我厌恶地认识到几乎没有程序工作正常。有大量的小错误(有些也不小),代码与输出之间的不兼容、排版等。谢谢Robert Spier在最后关头的英勇,我认为他捕获了这些错误里的大部分。Robert不仅确实是能干的、乐于助人的、富有成效的,而且确实是活泼开朗的。如果本书中的任何代码程序运行如预期,那么要感谢Robert。(如果不是这样,你应该责备我,而不是Robert。)Robert也负责命名我用来准备手稿的MOD文件准备系统。
我妻子Lorrie Kim的贡献太多太大以至于无法一一描述。本书题献给她。
其他许多人对本书作出了贡献,但是他们中许多人在当时并不知道。我幸运地拥有许多卓越的老师,我有时不得不狠狠地考验他们的忍耐力。谢谢Mark Foster、Patrick X. Gallagher、Joan Livingston、Cal Lobel(第一位教我编程的老师)、Harry McLaughlin、David A. J. Meyer、Bruce Piper、Ronnie Rabassa、Michael Tempel以及Johan Tysk。正当我认为一切都错过了的时候,Mark Foster鬼使神差地为本书建议了书名。
本书直接从两本更早的书获得灵感:《ML for the Working Programmer》,作者Lawrence Paulson,以及《Structure and Interpretation of Computer Programs》,作者Harold Abelson 和Gerald Jay Sussman。其他有重要影响的是《Introduction to Functional Programming》,作者Richard Bird 和Philip Wadler,以及《Paradigms of Artificial Intelligence Programming》,作者Peter Norvig。
正式的技术阅校者的工作报酬比他们可能在别的项目中更低。这本书花了很长时间写就,尽管我想与阅校者就每件小事进行长时间交谈,但是我害怕如果那么做了,我将永远也不会完成。所以我很少与阅校者联系,也许他们认为我只是把他们的建议塞进了碎纸机。但我不是那样的,我极其认真地仔细研究他们所有的批评,并为这些批评中的大多数伤脑筋。我要谢谢阅校者:Sean Burke、Damian Conway、Kevin Lenzo、Peter Norvig、Dan Schmidt、Kragen Sitaker、Michael Scott以及Adam Turoff。
媒体评论
你需要特为此书设置一个完全不同的隔板。
在第3章讨论缓存技术时,Mark Jason Dominus指出了在能力上一个足够巨大的改进以改变你思考技术的基本方式。那恰恰是这整本书为Perl所做的。
它探索了计算机科学最深的穹底与最高的塔尖,把它找到的许多晦涩难解的珍宝—递归、迭代器、过滤器、记忆术、划分、数值方法、高阶函数、currying、切断排序、基于语法的解析、惰性求值和约束编程等转换成现实编程工作中强有力与实用的工具—文件系统互动、HTML处理、数据库访问、网页抓取、排版、邮件处理、家庭理财、文本描图和图表生成。
一路上它也散布了小一些的(但是同样无价的)珍宝,如在第3章对“作用域”与“有效期”区别的优雅解释说明,或在第4章对返回错误标记有多么好的细致研究。它甚至对Perl传教士也有实用的妙法。
Dominus以简单和可理解的方式展现了甚至是最复杂的想法,但是在精确度与对细节的关注度上毫不妥协,为此他受到了广泛的与应得的尊敬。
他的作品是一如既往的清楚的、有说服力的、机智的以及引人入胜的。
命名巧妙,这确实是一本高阶Perl实战图书,也是每个严肃的Perl程序员的必备读物。
——Damian Conway
Perl 6设计者之一
书摘
递归与回调
本书将要介绍的第一个“高级的”技术是递归。递归(recursion)是一种解决问题的方法,它把问题简化成一个更简单的同类型问题。
不像本书中的大多数技术,递归已是众所周知并被广泛理解的。但考虑到它是后续几种技术的基础,因此我们需要很好地理解它的优点。
1.1十进制到二进制的转换
在Perl 5.6.0之前,在Perl中没有生成一个二进制数的好方法。从5.6.0开始,可以用sprintf("%b", $num),但之前这是一个令人备受困扰的问题。
任何整数都可以写成2k+b的形式,其中k是一个更小的整数,b是0或者1。b是二进制展开式的最末一位。判断这个最末位是0或者1很容易,只要看输入数是偶数还是奇数。剩下的数是2k,其二进制展开式和k一样,但要左移一位。例如,37=2×18+1,这里k是18,b是1,所以37的二进制展开式(100101)只需在18的(10010)末位添1即可。
如何计算37的展开式呢?它是个奇数,所以末位必为1,剩余的展开式部分和18一样。如何计算18的展开式呢?18是偶数,所以末位为0,剩余的展开式部分和9一样。9的二进制展开式是什么呢?9是奇数,所以末位为1,剩余的展开式部分和4一样。以此类推,直到最后1的二进制展开式,那当然是1。
这种方法适用于任何数。可以按照下面的过程计算一个数n的二进制展开式。
1)如果n是1,它的二进制展开式是1,就可以省略剩余的过程。类似地,如果n是0,展开式就是0。
2)否则:计算k和b使得n=2k+b且b=0或者1。为此,只需以2除n,k是商,b是余数,如果n是偶数,b是0,如果n是奇数,b是1。
3)用同样的方法计算k的二进制展开式。结果记为E。
4)n的二进制展开式是Eb。
创建一个称为binary()的函数计算展开式。开始第1步:
### Code Library: binary
sub binary {
binary my ($n) = @_;
return $n if $n == 0