王垠談?wù)Z法

使用和研究過這么多程序語言之后,我覺得幾乎不包含多余功能的語言纵搁,只有一個(gè):Scheme岳悟。所以我覺得它是學(xué)習(xí)程序設(shè)計(jì)最好的入手點(diǎn)和進(jìn)階工具队询。當(dāng)然 Scheme 也有少數(shù)的問題派桩,而且缺少一些我想要的功能,但這些都瑕不掩瑜蚌斩。在用了很多其它的語言之后铆惑,我覺得 Scheme 真的是非常優(yōu)美的語言。

要想指出 Scheme 所有的優(yōu)點(diǎn),并且跟其它語言比較员魏,恐怕要寫一本書才講的清楚丑蛤。所以在這篇文章里,我只提其中一個(gè)最簡單撕阎,卻又幾乎被所有人忽視的方面:語法受裹。

其它的 Lisp “方言”也有跟 Scheme 類似的語法(都是基于“S表達(dá)式”),所以在這篇(僅限這篇)文章里我所指出的“Scheme 的優(yōu)點(diǎn)”虏束,其實(shí)也可以作用于其它的 Lisp 方言棉饶。從現(xiàn)在開始,“Scheme”和“Lisp”這兩個(gè)詞基本上含義相同镇匀。

我覺得 Scheme (Lisp) 的基于“S表達(dá)式”(S-expression)的語法照藻,是世界上最完美的設(shè)計(jì)。其實(shí)我希望它能更簡單一點(diǎn)汗侵,但是在現(xiàn)存的語言中岩梳,我沒有找到第二種能與它比美。也許在讀過這篇文章之后晃择,你會(huì)發(fā)現(xiàn)這種語法設(shè)計(jì)的合理性,已經(jīng)接近理論允許的最大值也物。

為什么我喜歡這樣一個(gè)“全是括號宫屠,前綴表達(dá)式”的語言呢?這是出于對語言結(jié)構(gòu)本質(zhì)的考慮滑蚯。其實(shí)浪蹂,我覺得語法是完全不應(yīng)該存在的東西。即使存在告材,也應(yīng)該非常的簡單坤次。因?yàn)檎Z法其實(shí)只是對語言的本質(zhì)結(jié)構(gòu),“抽象語法樹”(abstract syntax tree斥赋,AST)缰猴,的一種編碼。一個(gè)良好的編碼疤剑,應(yīng)該極度簡單滑绒,不引起歧義,而且應(yīng)該容易解碼隘膘。在程序語言里疑故,這個(gè)“解碼”的過程叫做“語法分析”(parse)。

為什么我們卻又需要語法呢弯菊?因?yàn)槭艿浆F(xiàn)有工具(操作系統(tǒng)纵势,文本編輯器)的限制,到目前為止,幾乎所有語言的程序都是用字符串的形式存放在文件里的钦铁。為了讓字符串能夠表示“樹”這種結(jié)構(gòu)软舌,人們才給程序語言設(shè)計(jì)了“語法”這種東西。但是人們喜歡耍小聰明育瓜,在有了基本的語法之后葫隙,他們開始在這上面大做文章,使得簡單的問題變得無比復(fù)雜躏仇。

Lisp (Scheme 的前身)是世界上第二老的程序語言恋脚。最老的是 Fortran。Fortran 的程序焰手,最早的時(shí)候都是用打孔機(jī)打在卡片上的糟描,所以它其實(shí)是幾乎沒有語法可言的。

顯然书妻,這樣寫程序很痛苦船响。但是它卻比現(xiàn)代的很多語言有一個(gè)優(yōu)點(diǎn):它沒有歧義,沒有復(fù)雜的 parse 過程躲履。

在 Lisp 誕生的時(shí)候见间,它的設(shè)計(jì)者們一下子沒能想出一種好的語法,所以他們決定干脆先用括號把這語法樹的結(jié)構(gòu)全都括起來工猜,一個(gè)不漏米诉。等想到更好的語法再換。

自己想一下篷帅,如果要表達(dá)一顆“樹”史侣,最簡單的編碼方式是什么?就是用括號把每個(gè)節(jié)點(diǎn)的“數(shù)據(jù)”和“子節(jié)點(diǎn)”都括起來放在一起魏身。Lisp 的設(shè)計(jì)者們就是這樣想的惊橱。他們把這種完全用括號括起來的表達(dá)式,叫做“S表達(dá)式”(S 代表 "symbolic")箭昵。這貌似很“粗糙”的設(shè)計(jì)税朴,甚至根本談不上“設(shè)計(jì)”。奇怪的是宙枷,在用過一段時(shí)間之后掉房,他們發(fā)現(xiàn)自己已經(jīng)愛上了這個(gè)東西,再也不想設(shè)計(jì)更加復(fù)雜的語法慰丛。于是S表達(dá)式就沿用至今卓囚。

在使用過 Scheme,Haskell诅病,ML哪亿,和常見的 Java粥烁,C,C++蝇棉,Python讨阻,Perl,…… 之后篡殷,我也驚訝的發(fā)現(xiàn)钝吮, Scheme 的語法,不但是最簡單板辽,而且是最好看的一個(gè)奇瘦。這不是我情人眼里出西施,而是有一定理論依據(jù)的劲弦。

首先耳标,把所有的結(jié)構(gòu)都用括號括起來,輕松地避免了別的語言里面可能發(fā)生的“歧義”邑跪。程序員不再需要記憶任何“運(yùn)算符優(yōu)先級”次坡。

其次,把“操作符”全都放在表達(dá)式的最前面画畅,使得基本算術(shù)操作和函數(shù)調(diào)用砸琅,在語法上發(fā)生完美的統(tǒng)一,而且使得程序員可以使用幾乎任何符號作為函數(shù)名轴踱。

在其他的語言里明棍,函數(shù)調(diào)用看起來像這個(gè)樣子:f(1),而算術(shù)操作看起來是這樣:1+2寇僧。在 Lisp 里面,函數(shù)調(diào)用看起來是這樣(f 1)沸版,而算術(shù)操作看起來也是這樣(+ 1 2)嘁傀。你發(fā)現(xiàn)有什么共同點(diǎn)嗎?那就是 f 和 + 在位置上的對應(yīng)视粮。實(shí)際上细办,加法在本質(zhì)也是一個(gè)函數(shù)。這樣做的好處蕾殴,不但是突出了加法的這一本質(zhì)笑撞,而且它讓人可以用跟定義函數(shù)一模一樣的方式,來定義“運(yùn)算符”钓觉!這比起 C++ 的“運(yùn)算符重載”強(qiáng)大很多茴肥,卻又極其簡單。

關(guān)于“前綴表達(dá)式”與“中綴表達(dá)式”荡灾,我有一個(gè)很獨(dú)到的見解:我覺得“中綴表達(dá)式”其實(shí)是一種過時(shí)的瓤狐,來源于傳統(tǒng)數(shù)學(xué)的歷史遺留產(chǎn)物瞬铸。幾百年以來,人們都在用 x+y 這樣的符號來表示加法础锐。之所以這樣寫嗓节,而不是 (+ x y),是因?yàn)樵跊]有計(jì)算機(jī)以前皆警,數(shù)學(xué)公式都得寫在紙上拦宣,寫 x+y 顯然比 (+ x y) 方便簡潔。但是信姓,中綴表達(dá)式卻是容易出現(xiàn)歧義的鸵隧。如果你有多個(gè)操作符,比如 1+23财破。那么它表示的是 (+ 1 ( 2 3)) 呢掰派,還是 (* (+ 1 2) 3)?所以才出現(xiàn)了“運(yùn)算符優(yōu)先級”這種東西左痢∶蚁郏看見沒有,S表達(dá)式已經(jīng)在這里顯示出它沒有歧義的優(yōu)點(diǎn)俊性。你不需要知道 + 和 * 的優(yōu)先級略步,就能明白 (+ 1 (* 2 3)) 和 (* (+ 1 2) 3) 的區(qū)別。第一個(gè)先乘后加定页,而第二個(gè)先加后乘趟薄。

對于四則運(yùn)算,這些優(yōu)先級還算簡單典徊『技澹可是一旦有了更多的操作,就容易出現(xiàn)混淆卒落。這就是為什么數(shù)學(xué)(以及邏輯學(xué))的書籍難以看懂羡铲。 實(shí)際上,那些看似復(fù)雜的公式儡毕,符號也切,不過是在表示一些程序里的“數(shù)據(jù)結(jié)構(gòu)”,“對象”以及“函數(shù)”腰湾。大部分讀數(shù)學(xué)書的時(shí)間雷恃,其實(shí)是浪費(fèi)在琢磨這些公式:它們到底要表達(dá)的什么樣一個(gè)“數(shù)據(jù)結(jié)構(gòu)”或者“操作”!這個(gè)“琢磨”的過程费坊,其實(shí)就是程序語言里所謂的“語法分析”(parse)倒槐。

這種問題在微積分里面就更加明顯。微積分難學(xué)附井,很大部分原因导犹,就是因?yàn)槲⒎e分的那些傳統(tǒng)的運(yùn)算符唱凯,其實(shí)不是很好的設(shè)計(jì)。如果你想了解更好的設(shè)計(jì)谎痢,可以參考一下 Mathematica 的公式設(shè)計(jì)磕昼。試試在 Mathematica 里面輸入“單行”的微積分運(yùn)算(而不使用它傳統(tǒng)的“2D語法”)。

其實(shí) Lisp 已經(jīng)可以輕松地表示這種公式节猿,比如對 x^2 進(jìn)行微分票从,可以表示成

      (D ‘(^ x 2) ‘x)

看到了嗎?微分不過是一個(gè)用于處理符號的函數(shù) D滨嘱,輸入一個(gè)表達(dá)式和另一個(gè)符號峰鄙,輸出一個(gè)新的表達(dá)式。

同樣的公式太雨,傳統(tǒng)的數(shù)學(xué)符號是這個(gè)樣子:

這是什么玩意耙髁瘛?d 除以 dx囊扳,然后乘以 x 的平方吩翻?

在 Lisp 里,你其實(shí)可以比較輕松地實(shí)現(xiàn)符號微分的計(jì)算锥咸。SICP里貌似有一節(jié)就是教你寫個(gè)符號微分程序狭瞎。做微積分這種無聊的事情,就是應(yīng)該交給電腦去做搏予⌒芏В總之,這從一方面顯示了雪侥,Lisp 的語法其實(shí)超越了傳統(tǒng)的數(shù)學(xué)碗殷。

其實(shí)我一直都在想,如果把數(shù)學(xué)看成是一種程序語言速缨,它也許就是世界上語法最糟糕的語言亿扁。數(shù)學(xué)里的“變量”,幾乎總是沒有明確定義的作用域(scope)鸟廓。也就是說他們只有“全局變量”。上一段話的 x襟己,跟下一段話的 x引谜,經(jīng)常指的不是同一個(gè)東西。所以訓(xùn)練有素的數(shù)學(xué)家擎浴,總是避免使用同一個(gè)符號來表示兩種不同的東西员咽。很快他們就發(fā)現(xiàn)所有的拉丁字母都用光了,于是乎開始用希臘字母贮预。大寫的贝室,小寫的契讲,粗體的,斜體的滑频,花體的捡偏,…… 而其實(shí),他們只不過是想實(shí)現(xiàn) C++ 里的 “namespace”峡迷。

可惜的是银伟,很多程序語言的設(shè)計(jì)者沒能擺脫數(shù)學(xué)的思想束縛,對數(shù)學(xué)和邏輯有盲目崇拜的傾向绘搞。所以他們繼續(xù)在新的語言里使用中綴表達(dá)法彤避。Haskell,ML夯辖,Coq琉预,Agda,這些“超高級”的語言設(shè)計(jì)蒿褂,其實(shí)都中了這個(gè)圈套圆米。在 Coq 和 Agda 里面,你不但可以使用中綴表達(dá)式贮缅,還可以定義所謂的 "mixfix" 表達(dá)式榨咐。這樣其實(shí)是把簡單的問題復(fù)雜化。想讓自己看起來像“數(shù)學(xué)”谴供,很神秘的樣子块茁,其實(shí)是學(xué)會(huì)了數(shù)學(xué)的糟粕,自討苦吃桂肌。

最后数焊,從美學(xué)的角度上講,S表達(dá)式是很美觀的設(shè)計(jì)崎场。所有的符號都用括號括起來佩耳,這形成一種“流線型”的輪廓。而且由于可以自由的換行排版谭跨,你可以輕松地對齊相關(guān)的部分干厚。在 Haskell 里,你經(jīng)常會(huì)發(fā)現(xiàn)一些很蹩腳螃宙,很難看的地方蛮瞄。這是因?yàn)橹芯Y表達(dá)式的“操作符”,經(jīng)常不能對在一起谆扎。比如挂捅,如果你有像這樣一個(gè) case 表達(dá)式:

case x
Short _ -> 1
VeryLooooooooooooooooooooooooog _ -> 2

為了美觀,很多 Haskell 程序員喜歡把那兩個(gè)箭頭對齊堂湖。結(jié)果就成了這樣:

case x
Short _ -> 1
VeryLooooooooooooooooooooooooog _ -> 2

作為一個(gè)菜鳥級攝影師闲先,你不覺得第一行中間太“空”了一點(diǎn)嗎状土?

再來看看S表達(dá)式如何表達(dá)這東西:

(case x
(-> (Short _) 1)
(-> (VeryLooooooooooooooooooooooooog _) 2))

發(fā)現(xiàn)“操作符總在最前”的好處了嗎?不但容易看清楚伺糠,而且容易對齊蒙谓,而且沒有多余的間隙。

其實(shí)我們還可以更進(jìn)一步退盯。因?yàn)榧^的兩邊全都用括號括起來了彼乌,所以其實(shí)我們并不需要那兩個(gè)箭頭就能區(qū)分“左”和“右”。所以我們可以把它簡化為:

(case x
((Short _) 1)
((VeryLooooooooooooooooooooooooog _) 2))

最后我們發(fā)現(xiàn)渊迁,這個(gè)表達(dá)式“進(jìn)化”成了 Lisp 的 case 表達(dá)式慰照。

Lisp 的很多其它的設(shè)計(jì),比如“垃圾回收”琉朽,后來被很多現(xiàn)代語言(比如 Java)所借鑒毒租。可是人們遺漏了一個(gè)很重要的東西:Lisp 的語法箱叁,其實(shí)才是世界上最好的語法墅垮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市耕漱,隨后出現(xiàn)的幾起案子算色,更是在濱河造成了極大的恐慌,老刑警劉巖螟够,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灾梦,死亡現(xiàn)場離奇詭異,居然都是意外死亡妓笙,警方通過查閱死者的電腦和手機(jī)若河,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寞宫,“玉大人萧福,你說我怎么就攤上這事”哺常” “怎么了鲫忍?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長钥屈。 經(jīng)常有香客問我悟民,道長,這世上最難降的妖魔是什么焕蹄? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮阀溶,結(jié)果婚禮上腻脏,老公的妹妹穿的比我還像新娘鸦泳。我一直安慰自己,他們只是感情好永品,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布做鹰。 她就那樣靜靜地躺著,像睡著了一般鼎姐。 火紅的嫁衣襯著肌膚如雪钾麸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天炕桨,我揣著相機(jī)與錄音饭尝,去河邊找鬼。 笑死献宫,一個(gè)胖子當(dāng)著我的面吹牛钥平,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播姊途,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涉瘾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了捷兰?” 一聲冷哼從身側(cè)響起立叛,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贡茅,沒想到半個(gè)月后秘蛇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡友扰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年彤叉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片村怪。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡秽浇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出甚负,到底是詐尸還是另有隱情柬焕,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布梭域,位于F島的核電站斑举,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏病涨。R本人自食惡果不足惜富玷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赎懦,春花似錦雀鹃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至当悔,卻和暖如春傅瞻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盲憎。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工嗅骄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人焙畔。 一個(gè)月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓掸读,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宏多。 傳聞我的和親對象是個(gè)殘疾皇子儿惫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355

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

  • 第一部分Common Lisp介紹第1章 介紹一下Lisp你在學(xué)的時(shí)候覺得已經(jīng)明白了,寫的時(shí)候更加確信了解了伸但,教別...
    geoeee閱讀 2,946評論 5 8
  • 3.4 說說相等和內(nèi)部表示 在Lisp中主要有5種相等斷言肾请,因?yàn)椴皇撬械膶ο蟊粍?chuàng)建的時(shí)候都是相等意義上的相等。數(shù)...
    geoeee閱讀 1,819評論 0 6
  • Lisp的本質(zhì) - climbdream的個(gè)人空間 - 開源中國社區(qū)https://my.oschina.net/...
    葡萄喃喃囈語閱讀 699評論 0 10
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理更胖,服務(wù)發(fā)現(xiàn)铛铁,斷路器,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • From:http://emacsist.com/10845 點(diǎn) 這里 查看更多 Emacs 相關(guān)推薦文章 或 最...
    海神之奏閱讀 5,478評論 0 26