[Emacs] Emacs之魂(三):列表身笤,引用和求值策略

回顧

上文我們介紹了Emacs的用法豹悬,發(fā)現(xiàn)一分鐘學(xué)會使用它并不是難事,
而且液荸,我們沒有讓快捷鍵束縛住瞻佛,因為Emacs的精髓在于Emacs Lisp中。

本文我們開始探討Emacs Lisp娇钱,不過在這之前我們還要先熟悉一下Lisp的特點和Lisp家族的成員伤柄,
隨后本文重點分析和介紹了列表,引用和求值策略文搂,
這幾個概念适刀,尤其是引用,對學(xué)習(xí)者來說非常容易引起困惑煤蹭,
本文采用了不同的角度來描述這些概念笔喉。

1. 強(qiáng)大的Lisp

1960年取视,John McCarthy發(fā)表了一篇計算機(jī)領(lǐng)域的文章,這是一篇“驚世之作”常挚,
它的作用簡直就像歐幾里得《幾何原本》對幾何學(xué)的貢獻(xiàn)一樣作谭。
John McCarthy只用了一些簡單的的運算符和函數(shù),構(gòu)建出了一門圖靈完備的編程語言奄毡,
稱之為Lisp折欠,Lisp是列表處理(List Processing)的簡稱。
這門語言的關(guān)鍵思想是吼过,不論代碼還是數(shù)據(jù)锐秦,都用統(tǒng)一的數(shù)據(jù)結(jié)構(gòu)(列表)進(jìn)行表示。

Lisp語言具有很強(qiáng)的表達(dá)能力盗忱,我們可以用更少的代碼做更多的事情农猬。
通常而言,語言具有表達(dá)能力就必須提供豐富的內(nèi)置功能和強(qiáng)大的擴(kuò)展性售淡。

語言的內(nèi)置功能指的是語言默認(rèn)提供的功能斤葱,它能減少程序員的重復(fù)勞動,幫助他們快速完成工作揖闸。
語言的擴(kuò)展性揍堕,指的是當(dāng)語言內(nèi)置功能不能滿足需要的時候,程序員可以怎樣做汤纸。
同時具有豐富的功能和強(qiáng)大的擴(kuò)展性是很困難的衩茸,這需要在語言的設(shè)計階段就考慮好,
語言的內(nèi)置功能越多贮泞,就會越復(fù)雜楞慈,擴(kuò)展功能的與內(nèi)置功能的一致性就很難被保證。

現(xiàn)代的高級編程語言啃擦,離不開編譯器和解釋器囊蓝,
編譯器將高級語言的代碼轉(zhuǎn)換成更底層的語言,例如C語言或者匯編令蛉,
解釋器提供了一個運行時環(huán)境聚霜,直接解釋執(zhí)行高級語言的源代碼。

一般而言珠叔,編譯器是由語言的開發(fā)商提供的蝎宇,使用者并不會參與到編譯器的開發(fā)工作之中,
如果想要在語言中支持一等函數(shù)(first-class function)祷安,就必須讓語言的開發(fā)商改寫編譯器姥芥,
如果需要增加新的類似if-else的控制結(jié)構(gòu),或者讓語言支持面向?qū)ο缶幊袒惚蓿惨膶懢幾g器才行凉唐。
因此报嵌,語言支持什么功能,以及源代碼被如何編譯熊榛,完全取決于開發(fā)商。

而Lisp語言則不同腕巡,它允許程序員對編譯器進(jìn)行編程玄坦,(元編程
Lisp程序員可以決定代碼被如何編譯甚至如何被讀取,像是半個編譯器的開發(fā)者一樣绘沉。

2. Lisp-1和Lisp-2

Lisp語言構(gòu)成了一個家族煎楣,具有成百上千種方言,
用的最多的幾種是车伞,Common Lisp择懂,Scheme,Racket另玖,和Emacs Lisp困曙。
其中Scheme的目標(biāo)是簡潔,Common Lisp提供了強(qiáng)大的工業(yè)級支持谦去,
Racket提供了一種創(chuàng)造語言和設(shè)計實踐的平臺慷丽,Emacs Lisp主要用于Emacs中。

Emacs Lisp更像Common Lisp鳄哭,它們都是Lisp-2要糊,
即同一個符號在不同的上下文中,可以分別用來表示變量和函數(shù)妆丘,
而Scheme和Racket則只能用來表示同一個實體锄俄,稱為Lisp-1。

出現(xiàn)Lisp-2勺拣,主要是因為有效率方面的考慮奶赠,
在Lisp-2中,函數(shù)和變量分屬不同的名字空間药有,在不同的環(huán)境中车柠,由不同的求值器進(jìn)行處理。
這樣做也使語義更加復(fù)雜了塑猖,以后的文章中竹祷,我們會介紹Emacs Lisp中符號(Symbol)的概念。

3. 列表對象和它的文本表示

列表是Lisp語言中一種常用的數(shù)據(jù)結(jié)構(gòu)羊苟,用來表示一批數(shù)據(jù)塑陵。
例如,由整數(shù)1蜡励,23構(gòu)成的列表對象令花,Lisp會將它打印為阻桅,(1 2 3)
各個列表元素用空格分隔兼都,用圓括號括起來嫂沉。

然而,在Lisp代碼中直接寫(1 2 3)扮碧,并不會創(chuàng)建一個列表對象趟章,
因為Lisp程序也是用括號方式表示的,例如慎王,(+ 1 2)表示對整數(shù)12進(jìn)行加法運算蚓土。

那么如何才能創(chuàng)建一個列表對象呢?
我們需要調(diào)用list函數(shù)赖淤,(list 1 2 3)蜀漆,這段代碼將會創(chuàng)建一個由整數(shù)123構(gòu)成的列表對象咱旱,
這個列表對象打印為(1 2 3)确丢。

注意,以上我們嚴(yán)謹(jǐn)?shù)膮^(qū)分了Lisp對象和它的打印結(jié)果吐限,
是因為對象和它的文本表示(textual representation)是不同的概念蠕嫁。

例如,在C語言中我們寫毯盈,

int result = 1 + 2;

我們實際上是用“1”表示了整數(shù)1剃毒,“1”只是一段文本,是印刷符號搂赋,而整數(shù)1是一個數(shù)學(xué)對象赘阀,
同樣的,“+”是一段文本脑奠,它表示了加法運算符基公。

在Lisp語言中,我們用文本來寫程序宋欺,而Lisp讀取器得到的是Lisp對象轰豆,
經(jīng)過對這些Lisp對象進(jìn)行計算,得到了計算結(jié)果齿诞,也是一個Lisp對象酸休,
最終,反饋給我們的是這個對象的文本表示祷杈。

4. 字面量和引用

在Lisp中斑司,我們用文本“1”可以直接表示整數(shù)1,用“#t”表示真值但汞,
類似的“1”和“#t”宿刮,稱之為對象的字面量表示(literal representation)互站。

其它語言中,也提供了廣泛的字面量表示法僵缺,例如胡桃,JavaScript提供了數(shù)組和對象字面量,

const obj = {
    x: 1,
    y: [2, 3, 4]
};

這段代碼創(chuàng)建了一個JavaScript Object磕潮,它的x屬性值是1翠胰,y屬性值是一個數(shù)組。
字面量表示法揉抵,使得我們不必調(diào)用new Objectnew Array來創(chuàng)建它。

Lisp中列表對象用的非常多嗤疯,每次都使用list函數(shù)來創(chuàng)建是一件麻煩的事情冤今,
因此,Lisp語言提供了列表對象的字面量寫法茂缚,我們只需要調(diào)用quote就可以了戏罢。

(quote (1 2 3))

以上Lisp代碼會創(chuàng)建一個打印形式為(1 2 3)的列表對象。

對于嵌套列表脚囊,使用quote是非常方便的龟糕,

(quote (1 (2 3) ((4 5) (6 7))))

像這樣創(chuàng)建列表的方式,稱為引用(quoting)悔耘,
這不同于按引用調(diào)用(call by reference)中的“引用”(reference)讲岁。

quote還有一個便捷的寫法,就是用單引號來表示它衬以,(quote (1 2 3))可以表示為缓艳,

'(1 2 3)

我們只需要在列表前加一個單引號即可,因為列表的右括號表明了它在引用這個列表看峻。

5. quote和list

值得一提的是阶淘,引用并不保證每次都會重新創(chuàng)建列表。

例如互妓,在Lisp中我們使用define創(chuàng)建函數(shù)溪窒,

(define (foo)
    '(1 2 3))

然后,用以下方式進(jìn)行函數(shù)調(diào)用冯勉,注意foo參數(shù)個數(shù)為0個澈蚌,

(foo)

多次調(diào)用foo,編譯器可能返回同一個列表對象灼狰。

list則不同惜浅,每次調(diào)用它會返回一個全新的列表對象,

(define (foo)
    (list 1 2 3))

6. 求值策略

Lisp代碼是由表達(dá)式構(gòu)成的伏嗜,Lisp程序的執(zhí)行過程就是表達(dá)式的求值過程坛悉,

(* (+ 1 2) (+ 3 4))

以上表達(dá)式的求值結(jié)果為21伐厌。

在程序的列表表示法中,從左到右位于第一個位置的元素裸影,是比較特殊的挣轨,
它表示一個函數(shù)(function),一個宏(macro)轩猩,或者一個內(nèi)置的特殊命令(special form)卷扮。
位于其他位置的元素稱為參數(shù)。

函數(shù)被調(diào)用的時候均践,它的每個參數(shù)都必須首先被求值晤锹,
例如,以上程序中*彤委,+都是函數(shù)鞭铆,
在調(diào)用乘法函數(shù)*時,它的參數(shù)(+ 1 2)(+ 3 4)都首先要被求值焦影,分別求值為37车遂,
然后再進(jìn)行乘法運算,結(jié)果為21斯辰。

而宏和內(nèi)置的特殊命令舶担,并不要求如此,它們有自己的對參數(shù)的求值策略彬呻。

其中“1”稱之為自求值對象衣陶,對它進(jìn)行求值將得到它本身,

1
(eval 1)
(eval (eval 1))

其結(jié)果都為1闸氮,其它的自求值對象還包括布爾值祖搓,字符串,向量湖苞,等等拯欧。
(+ 1 2)12之前沒有quote,是因為它們是自求值對象财骨,(+ '1 '2)(+ 1 2)的計算結(jié)果是相等的镐作。

7. 在Emacs中求值表達(dá)式

Emacs可以直接求值文本中的Lisp代碼,我們只需要將光標(biāo)定位到列表尾部隆箩,
然后按快捷鍵C-x C-e即可该贾。(指的是按Ctrl+x,然后再按Ctrl+e

我們還可以試試quote和自求值對象捌臊,1求值為1杨蛋,'1求值為1

然而''1卻求值為(quote 1),是因為''1實際是(quote (quote 1))逞力,
它表示用字面量方式創(chuàng)建了一個形如(quote 1)的列表對象曙寡。

下文,我們來討論Emacs Lisp的控制結(jié)構(gòu)和基本的數(shù)據(jù)類型寇荧,
使用Lisp編程是一件有趣的事情举庶。

參考

The Roots of Lisp
Land of Lisp
Lisp in small pieces
An Introduction to Programming in Emacs Lisp
GNU Emacs Lisp Reference Manual

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市揩抡,隨后出現(xiàn)的幾起案子户侥,更是在濱河造成了極大的恐慌,老刑警劉巖峦嗤,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蕊唐,死亡現(xiàn)場離奇詭異,居然都是意外死亡烁设,警方通過查閱死者的電腦和手機(jī)替梨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來署尤,“玉大人耙替,你說我怎么就攤上這事亚侠〔芴澹” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵硝烂,是天一觀的道長箕别。 經(jīng)常有香客問我,道長滞谢,這世上最難降的妖魔是什么串稀? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮狮杨,結(jié)果婚禮上母截,老公的妹妹穿的比我還像新娘。我一直安慰自己橄教,他們只是感情好清寇,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著护蝶,像睡著了一般华烟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上持灰,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天盔夜,我揣著相機(jī)與錄音,去河邊找鬼。 笑死喂链,一個胖子當(dāng)著我的面吹牛返十,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播衩藤,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼吧慢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赏表?” 一聲冷哼從身側(cè)響起检诗,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瓢剿,沒想到半個月后逢慌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡间狂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年攻泼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鉴象。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡忙菠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纺弊,到底是詐尸還是另有隱情牛欢,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布淆游,位于F島的核電站傍睹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏犹菱。R本人自食惡果不足惜拾稳,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腊脱。 院中可真熱鬧访得,春花似錦、人聲如沸陕凹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捆姜。三九已至传趾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泥技,已是汗流浹背浆兰。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工磕仅, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人簸呈。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓榕订,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蜕便。 傳聞我的和親對象是個殘疾皇子劫恒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容