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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM