LISP看起来仍然不是进行文本操作的合适语言,而且我从Emacs库中看到的任何东西都不会让我有任何不同的想法。不过,它确实把Java语言打得天翻地覆。也许有一天会有人用Ruby作为嵌入式解释器来编写Emacs……。
这些都是很棒的观点。我很清楚他的感受。我非常了解查尔斯的感受,所以我决定写博客,而不是回复电子邮件。因为他提出的所有事情都是实实在在的问题。
让我们从一个基本问题开始考虑:Lisp对于文本处理有多好?事实证明,这是一个复杂的问题。
当我们想到文本处理时,我们中的大多数人通常会立即想到正则表达式。除非我们是C++程序员,在这种情况下,每当我们需要进行文本搜索时,我们都喜欢编写2500行的Unix实用程序的克隆-或者看起来是这样,来自我在过去几个月面试过的候选人。但我认为可以肯定地说,大多数程序员将文本处理等同于正则表达式。
Regexp显然非常有用。如果你现在不是非常精通正则表达式,那么你应该放下一切去精通它们。我敢打赌,我每年350天都会使用常规表达式:在我的编辑器中,在命令行中,在我的代码中-任何地方使用它都可以节省我的时间或使我的代码更清晰。哦,想想所有那些不知道如何使用regexp的所谓程序员是多么痛苦啊。啊.。让我们别再提这件事了。
然而,我在某处读到Lispers一直对正则表达式持怀疑态度,因为与可以对树结构进行的通用处理相比,正则表达式实际上有点弱。LISP人员会问:为什么要将数据存储为文本?(而不是将其存储为Lisp。)。
我不知道你怎么想,但我想到的第一个反应是:嗯,日志怎么样?我记得当时在想:天哪,一群失败者;Lisp的人甚至不知道几乎所有系统的日志都是一行条目,(到目前为止)最容易使用regexp进行解析。
然后,不到三周前,我注意到在Java1.5中,myjava.util.log输出已经悄悄地转换为XML。D';噢!Regexp处理XML很糟糕。如果你不知道为什么,请不要告诉我你不知道,否则我会恨你的。最好还是保持沉默。
那么,为什么日志要切换到XML输出呢?嗯,呃,啊,因为XML提供了比一行日志条目更强大、更通用的文本处理能力。我想是吧。实际上,我还没有完全习惯新的XML输出格式,但我正在尝试它,并试图学习喜欢它。它相当冗长,在某些情况下是好的,在另一些情况下可能不是那么好。
例如:日志中的Java堆栈跟踪将每个单独的堆栈框架条目包装在其自己的XML元素中。堆栈跟踪已经很长了,但这让它们有点疯狂。好吧,你来评头论足。您是否希望日志条目如下所示:
2005-02-21 6:57:39 PM java.util.logging.LogManager$RootLogger日志严重:发生了非常非常糟糕的事情!位于logtest.main(logtest.java:24)的java.lang.Exception。
<;?XML版本=";1.0";编码=";utf-8";独立=";no";?>;<;!DOCTYPE日志系统#34;logger.dtd&34;>;<;log>;<;记录>;<;Date>;Date>;2005-02-21T18:57:39<;/Date>;<;/Millis<;1109041059800;/Millis<;<;Sequence>;/Sequence<;/Sequence<;/LT;/Lgger>;<;Level>;Severe<;/Level>;<;class>;java.util.logging.LogManager$RootLogger<;/class>;<;method>;log<;/method>;<;线程>;10<;/线程>;<;message>;发生了一件非常糟糕的事情!<;/message>;<;异常>;message>;java.lang.Exception<;/message>;<;frame>;<;class>;Logtest<;/class>;<;method>;main<;/method>;<;line>;30<;/line>;<;/Frame>;<;/Exception>;<;/Record>;<;/log>;;
我想这要看情况了。如果您的日志只有几个条目,或者您只是在执行快速而肮脏的搜索,则常规表达式可能就足够了。但是有了大量的条目,XML(即使是冗长的五倍)成为了一个真正强大的工具。
例如,您可以在XML上执行XPath表达式-它们有点像正则表达式,但它们理解XML树结构:这是任何regexp(无论多么花哨)都无法实现的功能。使用一行XPath表达式,您可以(例如)选择具有包含特定Java类(或一组类)的堆栈跟踪的所有日志条目。尝试使用正则表达式可靠地做到这一点需要您花费时间、耐心和大量的辅助脚本。有了XPath,这就轻而易举了。
(顺便说一句,如果您还不是非常精通XPath,我建议您放下一切去精通它。PathExpression正变得非常流行,而XPath则处于领先地位,它们非常强大。如果您不知道如何使用XPath,您最终会在XML处理代码中糟糕地重新发明它。)。
XML数据还允许您使用XSLT转换(或者XQuery,如果您是硬核的,可能有点疯狂),或者您可以简单地用您喜欢的语言使用您最喜欢的SAX或DOM解析器,然后快速地做各种使用正则表达式会非常笨拙的事情。实际上,您只是在每个脚本中编写您自己的即席XML解析器。你就是不想去那里。
所以XML非常好。这在某种程度上验证了LispPeople一直以来的说法,那就是您甚至希望您的简单文本数据也是树形结构的。在Lisp中,等效的日志输出可能与XML非常相似:
(日志';(Record(Date";1109041059800-02-21T18:57:39";)(Millis 2005)(序列1)(记录器无)(严重级别)(类";java.util.logging.LogManager$RootLogger";)(方法';日志)(线程10)(消息";发生了非常糟糕的事情!";)(异常(消息";java.lang.Exception";)(Frame(class";logtest";)(method';main)(第30行)。
嗯..。相似的,除了更干净和更容易阅读的十倍。它仍然具有XML提供给您的所有相同的元数据,您仍然可以使用同样强大的工具(如果不是更强大的话)来处理它。
如果您足够愚蠢,甚至可以简单地将其转换为XML并使用XSLT。但是Lisp是直接可执行的,所以您可以简单地使标记名函数自动进行自我转换。它比使用XSLT容易得多,而且大小不到XSLT的十分之一。
对于您的XPath查询,有一些成熟的Common Lisp包直接支持XML和Lisp数据。方案也是如此。
我不在乎你的语言有多棒--C++、Ruby、Python、Java、Perl等等--我可以向你保证,即使它支持在语法树上执行XPath查询,以获取该语言的源代码(这是不太可能的),我也非常怀疑你是否愿意这样做。您看过Java或C++的ANTLR或JavaCC语法吗?Python和Ruby的语法几乎同样复杂。查询语言无法掩盖这种复杂性。用语法复杂的语言以编程方式处理源代码总是需要做更多的工作。
因此,除了Lisp社区之外,世界上的每个人都面临着相同的基本文本处理问题,我将对此进行总结:
要有效地做到这一点,您的数据必须是树形结构的。Regexp不会对任何足够复杂的数据或处理进行裁剪。
如今,对于大多数语言来说,您唯一真正的选择就是使用XML。它拥有所有最好的工具,并对您的语言提供最广泛的支持。
当您开始必须使用XSLT或XQuery,或者使用您喜欢的语言中的SAX或DOM解析器进行自己的转换时,本应简单的XML处理开始变得任意复杂。
在Lisp中,您的代码是数据,您的数据是代码,所以您还有第三个选择(除了regexp或XML),这在任何其他语言中实际上都不是一个选择:将文本数据存储为LISP程序。
如果您只是想要直观地扫描它,那么您可以自己看看,在我上面的例子中,它比XML更容易看起来。它也更小巧,在磁盘、网络、数据库等方面更容易使用。
如果您想要查询它,您可以加载它并使用Lisp函数,这些函数现在包括各种风格的路径表达式,如果您愿意的话,还可以包括XPath。
如果你想转换它,当然,你可以编写你自己的转换器,但是让实际代码知道如何自我转换可能更容易。在任何情况下,您的转换器都更容易编写,因为它们具有XSLT的所有优点(即转换器本身可以自动生成和自动转换,将事情分成多个很好的阶段),而没有XSLT的所有缺点(丑陋、粗暴、在聚会上没有乐趣,等等)。
当然,我们谈论的不仅仅是日志数据。对于配置文件来说,情况就更清楚了。您肯定希望它们是XML格式的,只是它有相同的问题,所以...。嘿,等一下-如果你的配置文件是...。口齿不清,那它就不是真正的.。配置文件不再是您的...的一部分。节目?是这样吗?
在Lisp世界中,整个令人讨厌的配置问题变得令人难以置信地更加方便。不再有节文件、apache-config、.properties文件、XML配置文件、Makefile-所有那些您希望是可执行的、拙劣的、半语言的生物,或者至少不需要特殊处理就直接加载到您的程序中。我知道,我知道--每个人都对分离你的代码和数据的力量赞不绝口。这是因为他们使用的语言根本不能很好地将数据表示为代码。但这才是你真正想要的,否则所有令人毛骨悚然的半种语言都不会朝着图灵完备的方向发展,不是吗?
事实上,如果你坚持代码/数据分离,而你又是OOP的倡导者,那么你就是在胡说八道。如果你对让日志条目知道如何自我转换或处理的直觉反应是哇,那就大错特错了,想想:你正在强加一个世界观来解决这个问题,这个世界观与你对数据封装和活动对象的概念不一致。这种世界观可以追溯到古代Unix和Unix之前的时代。但是如果你仔细想想,没有理由日志条目或配置文件不应该是可执行的和子类的。这样可能会更好。
那么,哦,网页呢?还是文字处理器文档?好吧,你自己想办法吧。网页使用HTML,它的功能甚至不足以表示文本样式,更不用说像晚行者那样的东西了。所以网页有CSS、JavaScript等等。它变得如此丑陋,以至于人们不再真正地写网页,也不再写制作用的东西。现在,人们把陈旧、肮脏的网络技术视为一种汇编语言。你用PHP、XML/XSLT、Perl/Mason或Java/JSP来编写代码,把你的页面分段组装起来,或者也许所有这些都放在一条巨大的uglypipeline中,它会编译成一种难以阅读的网页格式。说来有趣!
我可以坦率地告诉你:每个尝试这样做的人都会感到痛苦。世界上有很多人都在做我上面描述的事情。建设生产网站==痛苦。世界正在逐渐地、非常缓慢地向使用各种可执行的XML格式(例如,蚂蚁、果冻、茧)汇聚,这些格式……。嗯,它们在某种程度上缓解了痛苦,但它被新的痛苦所取代:可执行XML语言设计者对他们正在做的事情一无所知的痛苦。
所以现在Ant有了一个宏系统,Try/Catch标签,if标签,如果它还没有的话,它正逐渐迁移到图灵完整性(Turing-Complete)。但它仍然有从第一天起就存在的所有令人讨厌的问题:看起来像只能设置一次的变量的属性,以及标签工作方式的奇怪不一致,当然还有一个事实,即它自动地比编程语言冗长10倍,因为它是XML。别误会我的意思--它仍然比制造好得多。但是现在这个门槛不是很高,不是吗?
让我们面对现实吧:图灵完整的Ant(或Jelly,或任何纯XML处理框架)将是一个庞然大物,因为他们需要数年(如果不是几十年)才能弄清楚图灵完整性不等于表现力,他们将不得不添加词法作用域、数据类型、类系统和一流的函数,而且……。
我怎么会偏离文本处理的原始轨道这么远呢?嗯,这就是这个乱七八糟的故事的妙处:全是文本处理!日志文件、配置文件、XML数据、查询字符串、迷你语言、编程语言、转换器、网页、Word文档,应有尽有……。您的绝大多数编程工作都以某种方式涉及到文本处理。
你更愿意做什么?学习16种不同的语言和框架,以便进行简单的日志文件和配置文件处理?还是只需认真学习Lisp,所有这些问题就一劳永逸了?
这是一个反问句。在这一点上,答案显然是显而易见的:Lisp是邪恶的,从现在开始,你最好用C++、XML、JavaScript、PL*SQL、CSS、XSLT和正则表达式以及所有其他敬畏上帝的、热血的、充满爱国精神的全美语言来编写所有的代码。别再说这种疯狂的里斯普话了,听到了吗?
欢迎来到我的生活。我是加里·拉森漫画中的奶牛--抬起头,震惊地说:嘿,等一下!这是草!我们一直在吃草。";其他的牛茫然地盯着,嚼着草。
事实上,我确实觉得自己像那头牛,但我也觉得自己有点像萨尔曼·拉什迪(Salman Rushdie)的“午夜的孩子”(Midnight‘s Children)中的一个人物。(这是有史以来最令人惊叹的虚构作品之一,如果你没有读过,那你就错过了。)。有一个角色可以在时间中来回穿梭,所以他当然可以看到未来。有趣的是:所有其他孩子,即使他们知道他能预见未来,也拒绝相信他说的任何话。
是的,你可能会因为反对我上面的小讨论而勃然大怒。你认为我在小题大做,或者你认为我可能夸大了树形结构数据的重要性(也许你不是XML爱好者),或者你只是因为你不能真正清楚地说出我似乎有保罗·格雷厄姆-伊蒂斯(Paul Graham-tis)的原因而生我的气。我理解你的感受。
暂时把所有的喧嚣放在一边,让我们来谈谈查尔斯的第二个问题:如果Emacs是用Ruby编写的,不是更好吗?
毕竟,Emacs是为操作任何旧类型的文本而设计的,而不仅仅是像XML或Lisp这样的树形结构文本。当查尔斯在Emacs库中什么也没说时,他是对的,这表明Emacs-Lisp特别适合普通文本操作。它缺少了许多我们已经习惯的功能。Perl提高了普通/任意字符串处理的标准。
虽然从长远来看,基于Ruby的Emacs可能会相当不错,但我现在认为(甚至像我一样喜欢Ruby)Common LispEmacs会更好。我不想喋喋不休,因为如果你同意我的意见,那么你就不需要说服,如果你不同意,那么你很可能在任何合理的时间内都不会被说服。主要是,Lisp具有源自其s-表达式结构的固有的、无与伦比的技术优势,而Common Lisp已有20多年的成熟度,这使得它比Ruby或Python在很长很长一段时间内(如果有的话)具有更高的稳定性、性能和互操作性。
这就是问题所在:Emacs Lisp甚至比Common Lisp更早,而且它与Common Lisp(和Scheme更是如此)有一些不幸的不兼容之处,这使得向前移植变得如此重要,以至于几乎要完全重写。
由于Emacs是如此古老,有数百万行经过良好调试的ELISP代码;它是原始的、寿命最长的开源应用程序之一,因此您将有一个绝对巨大的任务来尝试重新实现所有这些代码。大多数尝试此功能的人最终都试图为旧的elispcode创建兼容模式。Guile Emacs、JEmacs和一些Common Lisp编辑器都试图做到这一点,但都没有成功。
另一种选择是只使用Emacs,因为它仍然是Lisp,甚至有一套相当全面的宏集,提供了很大的Common Lisp功能子集。因此,破解Emacs以与您的语言(或实际上是任何系统)进行互操作通常比尝试重新实现Emacs更容易。
不幸的是,如果人们可以直接进入并破解Emacs的源代码并修复问题,这真的不是什么大不了的事。例如,我喜欢添加与Perl5兼容的正则表达式,以及允许原始字符串的区域读取器-宏系统(或者至少在某些语法中进行修改以支持正则表达式,而不必对所有内容进行双重转义)。
但也有几个阻碍问题。其一,Emacs的民众对捐款的挑剔是出了名的--你必须提供法律文件,说明这些作品是你自己的,FSF可以使用它,等等。这是导致埃里克·雷蒙德(Eric Raymond)著名的大教堂和集市的基本问题--GNU Emacs就是原型大教堂。所以:祝您好运,让您的更改进入Emacs。Lucid家族尝试了一段时间,最终派生了代码库来生成XEmacs,这是出了名的糟糕情况。
贡献的困难超出了核心二进制文件的范围。比方说,如果你想贡献一个纯ELISP的字符串库(Emacs确实可以使用它),或者一个收藏包,我不确定你能不能做到。你必须通过RMS才能拿到它,这似乎相当令人望而生畏。RMS是,嗯,保守的-委婉地说。我认为他是个超级英雄,但他并不能让为Emacs捐款变得容易。
即使捐款不是一件麻烦的事,我们也不完全清楚Emacs是否值得一试。它缺少了许多相关引擎功能,而这些功能将使它能够执行比方说网络浏览器的工作。(工业和信息化部电子科学技术情报研究所陈皓)。让它达到可以呈现PostScript的程度似乎是一项不可能完成的任务。
而且许多新的程序员根本不使用Emacs;他们被Eclipse、IntelliJ、VisualStudio等IDE的诱惑力所吸引。Emacs的脸不是很漂亮(因为我上面提到的简单的渲染引擎),而且它肯定没有太多的市场。如今,大多数程序员都非常惊讶,竟然有人还在使用Emacs。如果他们意识到它有多么多的功能,以及它的可扩展性模型是多么强大,他们会感到十倍的惊讶。它得到了Eclipse可能永远不会有的东西,一百年内都不会有,这一点也不夸张。如果他们足够努力,他们最终会用Lisp重写其中的大部分内容,总而言之,这将是非常具有讽刺意味的。
所以!。这种情况最好用进退两难来形容。Emacs正在不断进步,要用另一种语言重新实现似乎有很多工作要做。(并不是说像狡猾的人这样的人正在努力,但它仍然在努力。
.