unix開發人員(以下簡稱ud, unix developer):我再也不會碰lisp了。太可怕了!
我:為什麼這麼說?
ud:它的語法!那個波蘭式的字首語法看得眼睛都花了,也就只有它在用了。你看看這些個括號!
我:好吧,但很多人認為這個可讀性很強,儘管他們也承認是得花點時間才能習慣它。但我覺得你錯了。很多人其實每天都在使用lisp語法。。。
ud:據我所知,沒人像你說的這樣。
我:。。他們可能自己都沒意識到這個。事實上,我認為你也在使用它。
ud:等等,你說什麼?!
我:你用的這個特殊的lisp語法的變種又叫做bourne shell。
ud:這我可聽不明白了。shell和lisp有毛關係?
我:你看下shell裡面,你先輸入程式名,然後是引數,它們用空格為分隔開。lisp裡面也是這樣的,只不過你放了乙個左括號在前面,最後又加上了乙個右括號。
shell: run-something arg1 arg2 arg3
lisp: (run-something arg1 arg2 arg3)
ud: 我還是沒感覺有什麼像的。
我:現在你需要一種機制將表示式組合起來——也就是將乙個表示式的輸出作為另乙個表示式的輸入。在lisp裡面,你需要巢狀列表了。那麼在shell裡呢?
ud:`
我:對的。或者是$(),它的好處是更容易巢狀了。我們來試一下算術運算。你在shell裡是怎麼進行數**算的?
ud: expr。或者shell內建的let,比如這樣:
$ let x='2*((10+4)/7)'; echo $x
4
我:這個可能有點不太符合unix的精神了——乙個程式應當只做一件事情——我們應該有乙個程式來做加法,乙個做減法,還有的分別做乘法和除法。
用c來寫乙個的話很簡單:
#include
#include
#include
int main(int argc, char **argv)
if (mode == -1)
if ((mode == 1 || mode == 3) && !cnt)
switch (mode)
while (cnt--)
}printf("%d\n", val);
return 0;
}
這個程式是根據名字的最後乙個字元進行分發的,因此你可以將它編譯成+,-, x和d(這裡乘法和除法用的名字不太常用,因為這是合法字元也省得轉義了)
現在看吧:
$ x 2 $(d $(+ 10 4) 7)
4
ud: 好吧,這真的看真來很像lisp了。
我:是的,但這就是shell。我們的兩個基本原則——程式名在前,$()用來組合操作——這樣就能明確區分出求值的順序,也不需要做額外的解析了,因為shell已經提供了這樣的功能。
ud:那麼shell也是lisp的一種嗎?
我:不算是。shell是字串型別的:程式接收文字引數,輸出的也是文字的結果。要想成為lisp中的一員,它還得有乙個組合型別:列表或者cons單元,你可以用它來構建列表。然後,你還需要能夠用資料結構來表示**,可以編寫程式來對**進行轉化。
不過,shell的語法中蘊含著lisp之道。
我知道我這裡漏掉了許多細節,比如shell的重定向,命令替換,子程序,程式除了命令列引數外還有標準准入,以及管道,等等——這些都使得shell看起來不那麼像lisp。不過我認為這是向大家介紹lisp語法的乙個很有趣的方式。
error LNK2005 已經在 obj中定義
為什麼會出現這個錯誤?error lnk2005 已經在 obj中定義 程式設計中經常能遇到lnk2005錯誤 重複定義錯誤,其實lnk2005錯誤並不是乙個很難解決的錯誤,弄清楚它形成的原因,就可以輕鬆解決它了。造成lnk2005錯誤主要有以下幾種情況 1 重複定義全域性變數。可能存在兩種情況 a...
error LNK2005 已經在 obj中定義
為什麼會出現這個錯誤?error lnk2005 已經在 obj中定義 程式設計中經常能遇到lnk2005錯誤 重複定義錯誤,其實lnk2005錯誤並不是乙個很難解決的錯誤,弄清楚它形成的原因,就可以輕鬆解決它了。造成lnk2005錯誤主要有以下幾種情況 1 重複定義全域性變數。可能存在兩種情況 a...
error LNK2005 已經在 obj中定義
為什麼會出現這個錯誤?error lnk2005 已經在 obj中定義 程式設計中經常能遇到lnk2005錯誤 重複定義錯誤,其實lnk2005錯誤並不是乙個很難解決的錯誤,弄清楚它形成的原因,就可以輕鬆解決它了。造成lnk2005錯誤主要有以下幾種情況 1 重複定義全域性變數。可能存在兩種情況 a...