博客园  :: 首页  :: 联系 :: 管理

emacs的问题

Posted on 2012-11-20 21:53  雪庭  阅读(2824)  评论(1编辑  收藏  举报
emacs的问题

emacs的问题

1 本文译自Steve Yegge的博客,原文在:

1.1 Charles G. 最近在一封电子邮件中指出:

Lisp并不象适合处理文本的语言,即使在读过了Emacs的源码库以后也不能改变我的这一 印象。 当然,它比Java强得多。 也许有一天有人会用Ruby作内置的解释器把Emacs重写 一遍。

这是很不错的看法。我很清楚他想说什么。我决定写一篇博客,而不是回一封电子邮件。因 为他提到这些问题非常现实,绝非无中生有。

1.2 Lisp用作文本处理

让我们从基本的问题开始:用Lisp来作文本处理究竟有多好?这实际上是个相当复杂的问题。

在思考“文本处理”的时候,多数人会马上想到正则表达式,除非你正好是个C++程序员,那 么你会写一个两千五百行的程序把UNIX的grep重新实现一遍来作文本查询。这是我从过去几 个月的面试中得到的印象。不过我认为对于大多数程序员来说,文本处理就意味着正则表达 式。

正则表达式显然非常有用。如果你还没有完全掌握它,你应该放下手头的一切,马上去学习。 我每年至少有三百五十天要用到正则表达式:在我的编辑器里,在命令行里,在我写的代码 里,如果用正则表达式会让代码更加简单清晰。唉,一想到有那么多所谓“程序员”根本不 懂使用正则表达式,我的心都碎了。算了,先不谈这个。

然而,我在什么地方读到过说Lisp程序员对正则表达式不那么感冒,因为和对树状数据结构 的通用处理比起来,正则表达式有一点弱。Lisp程序员们问道:为什么从一开始要把数据放 在文本里?(相对把数据放在Lisp里)

我不知道你会怎么样,不过我的第一反应是:“哈,你拿log怎么办?”我当时是这样想的: 这些人真够傻,居然不知道几乎所有系统的log都是一行一行的文本记录,最方便的就是用正 则表达式来处理。

是啊,拿log怎么办?这些笨蛋Lisp程序员,傻B,笨蛋。我可将了他们一军。

不过不到三周之内,我注意到在Java 1.5里, java.util.logging的输出格式变成了XML。 啊!正则表达式处理XML可不怎么出色。如果你不知道为什么,别告诉我你不知道,否则我会 恨你。还是保持沉默吧。

那么为什么log文件的格式会变成XML?嗯,这个,因为XML可以提供更加强大通用的文本处理 能力。我认为。实际上我还没有完全适应新的XML格式,不过我正在努力学习,还慢慢开始喜 欢上了它。它非常罗嗦,有些情况下这是好事,另外一些情况下,不见得是好事。

现在来研究一下:Java在log里把每一个栈幅都用XML元素包装了起来,堆栈纪录是相当的 长,结果log看上去有点疯狂。咳,你自己下结论吧,看看是不是愿意你自己的log看上去象 是这样:

Feb 21, 2005 6:57:39 PM java.util.logging.LogManager$RootLogger logSEVERE: A very very bad thing has happened!java.lang.Exception at logtest.main(logtest.java:24)

还是这样:

<?xml version="1.0" encoding="utf-8" standalone="no"?> <!DOCTYPE log SYSTEM "logger.dtd"> <log> <record>
   <date>2005-02-21T18:57:39</date>
   <millis>1109041059800</millis>
   <sequence>1</sequence>
   <logger></logger>
   <level>SEVERE</level>
   <class>java.util.logging.LogManager$RootLogger</class>
   <method>log</method>
   <thread>10</thread>
   <message>A very very bad thing has happened!</message>
   <exception>
     <message>java.lang.Exception</message>
     <frame>
       <class>logtest</class>
       <method>main</method>
       <line>30</line>
     </frame>
   </exception>
</record>
</log> 

大概是根据实际情况决定吧。如果你的log只有几条纪录,或者你只想做快速查找,正则表达 式也许已经足够。不过对于大量的纪录来说,XML(虽然它要罗嗦五倍)才是真正强大的工具。

比如说,你可以对XML使用XPath。这有点象正则表达式,只是它理解XML的树状结构。而这正 是正则表达式永远也做不到的,无论怎么花哨。举例来说,用一行XPath表达式,你就可以在 所有的log纪录里挑出所有包含某一特定Java类的堆栈纪录。想用正则表达式达到同样的可靠 性需要时间,耐心,和一大堆的辅助脚本。而用XPath就是一下子的事情。

(打断一下,如果你还没有完全掌握XPath,我建议你放下手头的一切,马上开始学习。路径 表达式正在开始流行,而XPath是其中的翘楚。它们非常强大。如果你不知道如何使用 XPath,你会不得不在自己的XML处理代码里以糟糕的方式重新实现它的功能。)

XML数据还允许你使用XSLT(或者XQuery,如果你是个神经不太正常的死硬派),或者在你熟 悉的语言里使用SAX或者DOM解释器。这样就可以很便捷地做一些用正则表达式做起来很繁琐 的事情。繁琐也不算什么,实际上你得在每个脚本程序写个新的XML解释器,相信你不会这么 傻。

所以XML相当不错。这正证明了那些Lisp程序员一直在说的,就是把即使是“简单”的文本数 据也树形结构化。在Lisp里,相对的log格式看上去很象XML:

(log
'(record
   (date "2005-02-21T18:57:39")
   (millis 1109041059800)
   (sequence 1)
   (logger nil)
   (level 'SEVERE)
   (class "java.util.logging.LogManager$RootLogger")
   (method 'log)
   (thread 10)
   (message "A very very bad thing has happened!")
   (exception
     (message "java.lang.Exception")
     (frame
       (class "logtest")
       (method 'main)
       (line 30))))) 

嗯,有点象。只不过清晰十倍,好读得多。仍然有和XML同样的元数据,仍然可以用强大的工 具来作处理,甚至更强大。

甚至可以很方便地转化成XML,再使用XSLT,如果你够傻。不过Lisp可以直接执行,所以你可 以把标签的名字变成函数,自动翻译数据。这比用XSLT容易多了,而代码大小缩水到十分之 一不到。

XPath查询嘛,嗯,在Common Lisp中有许多成熟的软件包来直接查询XML和Lisp数据。在 Scheme里也有。

我不管你用的语言是C++,Ruby,Python,Java还是Perl。我可以保证即使它支持用XPath查 询来解释语法树,你也不想这么做。你有没有看过ANTLR或JavaCC的语法?而Python和Ruby的 语法同样复杂。查询语言无法掩盖其复杂性。程序化地处理复杂语言的源代码需要更多的工 作。

1.3 文本处理之谜

那么除了Lisp程序员以外的所有人都面临着相同的根本文本处理问题,我在此总结如下:

存储和处理文本数据

高效解决问题要求树状结构。正则表达式对于处理复杂数据可以说是无能为力。

XML处理应该很容易,可是一旦开始使用XSLT或者XQuery或者在你拿手的语言里使用SAX/DOM 解释器其复杂度就开始无限增长。

不过对你来说别无选择。

在Lisp里,代码就是数据,数据就是代码。所以还有除了正则表达式和XML以外的第三选项: 把文本数据存放在Lisp程序里。

如果你只想迅速地浏览一下,呵呵,你可以自己看看我上面的例子,比XML好读多了。而且更 加紧凑,对硬盘、网络、数据库和IDE来说都是好事。

如果想查询,只需加载后使用Lisp函数,现在可以使用的已经包括各式各样的路径表达式, 也有XPath,如果你愿意用。

如果想转换,当然,可以自己写转换器。不过让代码自己知道如何转换岂不是更加方便?不 管怎样,写个转换器会更容易,因为XSLT的好处我们都有(比如,转换器自己可以被自动生 成和自动转换,把整个过程分成不同的阶段),而没有XSLT的缺点(丑陋,臃肿,不适合开 party时谈论,等等)。

1.4 不止是log

我们当然不只是在讨论Log数据。当考虑配置文件的时候情况更清楚。你绝对想要XML格式, 可是面临同样的问题:所以···等等,如果配置文件格式是···Lisp,那么它实际上就···不再 是配置文件,而成为···程序的一部分?是不是这样?

啊,嗯,没错。你明白了。

讨厌的“配置”问题在Lisp世界里变得无比方便。不再需要那些象歌词似的文 件,apache-config, .properties文件, XML配置文件,Makefiles和所有那些你希望能直接 执行或者至少能直接加载进程序的破烂玩意儿。我明白,我明白大家都在宣扬把数据和代码 分开的力量。因为大家使用的语言都无法做到把数据作为代码。但是这才是你真正需要的, 或者那些配置文件用的半成品语言也许会进化到具有图灵完备性?

事实上,如果你一定要坚持数据与代码分开,而又同时是面向对象编程的拥护者,那你不过 是说胡话。如果你对能够自我转换或者自我处理的log纪录的本能反应是“瞎搞!”再开动脑 筋想一想:你强加在此问题上的世界观与数据封装和对象的概念是有冲突的。这种世界观可 以追溯到Unix和Unix以前的时代。但是仔细琢磨一下,没有理由认为log纪录和配置文件就一 定不能执行或者被继承。能执行,能被继承可能更好。

那网页呢?字处理文件?嗯,你一定想到了。网页用的是HTML,一种连文本样式都处理不好 的格式,更不用说事件处理了。所以网页要用到CSS,以及Javascript,以及其它一堆乱七八 糟。这东西已经变得如此不堪,以至已经没有人在工作系统上写正儿八经的网页了。现在大 家把这种陈旧发霉的网络技术当作汇编语言来看待。网页的各个组成部分先用PHP或者 XML/XSLT或者Perl/Mason或者Java/JSP或者甚至所有这些都用一点的巨大丑陋的流水线写出 来,再写代码把这些组成部分拼装起来,然后“编译”生成无法阅读的网页格式。真是好玩 极了!

我实话告诉你:干这个的都很痛苦。而世界上就有无数人干着我刚刚描述过的工作。建造网 站 == 痛苦。这个世界正在逐渐地、缓慢地向着一些“可执行的XML”演进(比如Ant, Jelly,Cocoon)。它们在某些方面减轻了痛苦,但同时又带来了新的痛苦:可执行的XML语 言的设计者们根本不知道自己在做什么。

那现在Ant有了一个宏系统,以及try/catch标签,正在向具有图灵完备性的方向发展。可是 它从最一开始就有的问题还没解决:属性象变量,可是只能赋一次值;还有奇怪的标签的不 一致性;当然还有比编程语言罗嗦十倍,因为它是XML。别误会,比起Make来是好得多了,不 过这标准也太低了点儿,是不是?

还是直面现实吧:具有了图灵完备性的Ant(或者Jelly,或者任何纯XML处理框架系统)会是 一个怪物,因为这些人要花上几年(如果不是几十年)才能认识到图灵完备性不等于表现 力,为此还不得不加入变量范围,以及数据类型,以及类系统,以及系统级的函数,以及以 及以及···

说到底,它还是XML。

我是怎么不着边际地离题万里地扯到这儿的?呵呵,整个故事的精华在于:这些全都是文本 处理!Log文件,配置文件, XML数据,查询语句,袖珍语言,编程语言,转换器,网页,字 处理文件,一切的一切···你编程工作的绝大部分都与文本处理有关。

你会怎么办?学习十六种不同的语言和框架来作“简单”的log文件和配置文件处理?还是干 脆投降,学习Lisp,让这一切问题永远消失?

这是个设问,答案在此刻是如此明显:Lisp是邪教,你还是用C++和XML和Javascript和 PL*SQL和CSS和XSLT和正则表达式和所有其它敬畏上帝、血统纯正、爱国爱家的语言写代码, 直至白发千古。少提Lisp,听见没有?

欢迎来到我的生活,我就是Gary Larsen漫画里的那头牛:震惊地说道:“嘿!等等!这是 草!我们一直在吃草!”其它的牛们茫然地瞪着,继续吃草。

实际上我确实感觉自己象那头牛,不过也有一点觉得象萨尔曼·拉什迪的“午夜孩子”里的一 个人物。(这是史上最强的小说,如果你没读过,那是一大憾事)该人物可以作时间旅行, 所以知道将来是怎么回事。可笑的是:其他人虽然知道他可以预测未来,却拒绝相信他说的 一切。

是啊,说不定你就在那里对我的小小讨论大发雷霆。你觉得我把有些事情想得太简单,或者 大大高估了树状结构的重要性,或者你只是为了一些自己也说不清的原因生我的气。我理解 你的感受。

具有预测未来的能力实际上并不愉快。

1.5 和Emacs有什么关系?

先不胡扯,让我们说说Charles的第二个问题:把Emacs用Ruby重写是不是更好?

毕竟Emacs是为了操作文本而设计的,任何格式的文本,不只是树状结构的文本比如XML或者 Lisp。当Charles说Emacs的软件库里没有什么能说明Emacs-Lisp处理起普通文本来是特别的 出色的时候,他说得对极了。它缺乏许多我们已经习已为常的功能。Perl在处理普通/任意的 字符串方面把标准提高了不少。

虽然一个基于Ruby的Emacs在许多方面会很不错,但我现在认为(别忘了我也很喜欢Ruby)一 个基于Common Lisp的Emacs会更好。我不想多说,因为如果你同意那我无须多说。而如果你 不同意,那我说什么也没有用。简单地说就是Lisp拥有的符号表达式结构所带来的内在的、 无可媲美的技术优势,而Common Lisp的二十多年的历史所带来的稳定性、性能和外联能力是 Ruby或Python很长时间之内所赶不上的。

那么,为什么不把Emacs换成Common Lisp?

这就是难点:Emacs Lisp甚至比Common Lisp还老,在很多方面不幸与Common Lisp不兼容。 把Emacs变成Common Lisp几乎就是要从头重写。

Emacs是如此古老,其中有数以百万行计的经过检验、测试的代码。它是最原始、最长寿的开 源软件之一,要重写一遍绝非易事。大多数想试试的人最终选择了对旧的elisp代码实行“兼 容模式”。Guile Emacs,JEmacs和几个Common Lisp编辑器都试图这样,不过目前还没有成 功的范例。

另一个办法是凑合着用Emacs,既然它仍然是Lisp,而且有一套相当广泛的宏来实现Common Lisp的功能。所以一般说来还是修改Emacs来为你的语言或系统服务更容易一些。

不幸的是,让大家直接修改Emacs源码也非易事。比如,我就很想加入Perl-5里的正则表达 式,以及一个宏系统来允许原始字符串,或者至少修改一下正则表达式的语法,不用什么字 符前面都要加两个斜杠。

可是这里有几大障碍。一是Emacs程序员对代码提交是出了名的挑剔。你得提交法律文件来证 明代码是自己写的,FSF可以使用等等。就是这个问题促使Eric Raymond写了“大教堂和市 集”。 GNU Emacs就是那大教堂。如果你想提交代码,祝你好运!Lucid程序员们曾经试过, 最后分出了自己的XEmacs,那东西现在可是情况不大妙。

为Emacs做贡献的困难不仅仅在于核心的二进制代码部分。如果你想贡献一个纯用Elisp写的 字符串库(Emacs确实需要这样的库),或者数据结构包,我不太觉得你能成功。你得通过 RMS的审核,那是相当的困难。RMS嘛,说得好听一点,有些保守。我认为他是个超级英雄, 就是让为Emacs贡献代码困难了一点点。

即使贡献代码不是这么困难,修改Emacs对许多人来说也不一定是件划算的事情。它没有渲染 引擎来干一些比如网络浏览器之类的活。就连显示PostScript也是不可能的任务。

新程序员们根本就不用Emacs,他们被诸如Eclipse、IntelliJ、Visual Studio之类的华丽 IDE吸引走了。Emacs没有长一张漂亮的脸(因为我上面说的渲染引擎问题),当然也没有人 给它做市场营销。大多数程序员会为居然还有人用Emacs而感到吃惊。如果他们能意识到 Emacs有如此多的功能,以及可扩展的结构有多么强力,他们会更吃惊十倍。它的一些东西 Eclipse永远也不会有,一百年也不会,这一点也不夸张。如果Eclipse的程序员们努把力, 也许应该用Lisp把大部分Eclipse重写一遍,那可是相当相当地讽刺啊。

1.6 Emacs问题

好了!现在这样子也许最适合用“僵局”来形容。Emacs并没有在真正进步,而用另一门语言 重写所涉及的工作量实在太大了(倒也不是没有人在试,比如Guile,可是目前为止没有什么 进展)。现在在流行一堆没那么强大的语言,事实上我觉得语言的流行程度和它的强大成反 比。只是大家都意识不到自己错过的是什么。

所以,是的,Charles是正确的。Lisp并不是处理文本的最佳语言,至少当你认为文本处理就 是正则表达式语法(以及字符串置换,以及其它一些Perl里的名堂),而且你只看了和 Emacs绑在一起发行的库。

当然,比Java那是强得太多了,至少在做可以动态改变的IDE方面。我不能讲太多,否则会被 板砖砸死。

也许,仅仅是也许,有人将来会成功地用另一种高级语言来写一个Emacs的替代品。这个将来 不会太近,我敢打赌。

现在我使用的工具有不少:Perl/Python/Ruby来写脚本, Java或者C来写大型系统,XML来放 数据;甚至用Eclipse写过一点东西。而Emacs是一个很好的、通用的、可扩展的编辑器和开 发环境,特别是当你努力掌握了它以后。可是大家都知道现在的情况(考虑网络编程,别忘 了)显然不是太好。

这是个难题。

Date: 2012-11-20 21:58:48 CST

Author: machine of awareness

Org version 7.8.06 with Emacs version 23

Validate XHTML 1.0