为什么“无人问津”的Lisp可以这么狂?
一到周末,Hello World 咖啡館就比平時熱鬧得多, 各種語言都來到這里,互相打探對方的最新特性,看看自己能不能借鑒一些。?
這天晚上,由于Lisp的到來,咖啡館的氣氛顯得格外熱烈。?
Lisp
Lisp身穿一身時髦又奇異的括號服裝, 和Clojure, Scala等幾個函數式編程的忠實擁躉坐在一桌,談笑風聲,時不時挖苦一下隔壁的幾個人,那里坐著以C語言為首的幾個大佬。?
他悠閑地端起了一杯咖啡,悠悠地說道:“聽說Java也用上了函數式編程? ”
Clojure道:“是啊,加上去沒多久,好多人還沒用熟呢!”
Lisp不屑地說道:“加上了也沒用,不是我瞧不起他們,表達能力實在是太弱了!”
隔壁的C語言早就憋了一肚子火, 聽到這句話,忍不住說道:“你嘚瑟什么呀,我知道你是基于Lambda演算的,但我們是基于圖靈機的啊,?上世紀已經證明這圖靈機和Lambda演算是等價的,所以我們的能力是一樣的。 對了,你知不知道什么是圖靈機,以及他的實現馮諾依曼架構啊?”
Lisp懶懶地說:“沒興趣了解,理論上計算能力是等價的,但并不代表在語言層面的表示一樣,比如說,在我這里非常自然的函數式編程,在你們那里看起來就很別扭,是不是啊Java老弟?”?
Java有點不好意思,他很清楚,自己的函數式編程就是一個半吊子,所謂的Lambda表達式就是個接口實現而已。
(詳情參見:《Lambda表達式有什么用?》)
Python出來解圍:“ 我這里支持得很好啊,? 我可以把函數當做參數進行傳遞,可以把函數當做返回值返回,還可以把函數保存到數據結構中!高階函數map, reduce用起來也賊爽。”
JavaScript接口道:“我也是啊!”
程序就是數據
Lisp 笑了一下,接著問道:“你們能在運行時創建新的函數嗎?”
Java 看到展示自己的機會來了,馬上接口道:“怎么不能? 在程序運行的時候,我可以通過操作Java字節碼的方法,動態地生成函數和類,人們經常說的AOP就是這么玩的。”
Lisp很不屑:“還操縱字節碼,還AOP,麻煩不麻煩!? 低級不低級!丟人不丟人! ”
Java一臉愕然。
Lisp開始放大招: “你們能不能寫個函數,把代碼傳遞進去,然后對代碼進行修改,然后返回新的代碼?”
一個修改代碼的函數?? 代碼可以在運行時修改? 這不是自虐嗎?
“哈哈,這你們就不懂了吧, 憑什么數據結構可以變化,并且其中的數據可以修改,而程序卻不能呢?在我這里,代碼就是數據,代碼可以在運行時被修改。”? Lisp很得意。
JavaScript憤憤地說:“這有什么鳥用?”
Lisp看了看身邊的Java ,又拿他開刀:“就拿你來舉例吧, 你最早只有for 循環,沒有for each 循環, 就是下面這樣, 是不是被很多人罵啊?”
普通for 循環
for(int?i=0;i<persons.size();i++){Person?p?=?persons.get(i);System.out.println(p); }for each 循環
for?(Person?p?:?perons){System.out.println(p); }Java無奈地點點頭,Lisp說的是實話。
“這就是了,要想把這個新的語法給加上,那必須得在語言層面修改才行,對吧? 語言不支持,程序員罵也沒用。 但是在我Lisp里就不一樣了,根本就不用改動語言,一個程序員就能把這個新的語法給加上,并且新的for each 和 老的for 處于同等地位,相當于語言被擴展了。 ”
“不會吧,你怎么實現?”?
“自然是使用宏(Macro)了!”
“什么是宏? 和C老大的宏一樣嗎?” Java問道。
“C語言的宏就是編譯期的文本替換而已,怎么能和我的宏相比? 給你說你也聽不懂,通俗點說宏也是程序員寫的代碼, 運行時可以把代碼傳遞給宏,然后宏可以修改這段代碼,返回新的代碼。 拿剛才的例子來說,假設for是個函數,程序員可以寫一個for-each 的宏,在這個宏中,修改/擴展for函數的代碼,實現for each的功能。”
C語言若有所思:“嗯,看來在你這里,程序也是數據啊,可以任意操作,果然厲害。如果把一段程序看成是抽象語法樹(AST),那這個宏就相當于把AST做了修改,形成了新的AST。”
Lisp心想,這老家伙還不賴, 已經Get到了。??
他說:“你們老是笑話我的括號多,但是你們不明白的是,這恰恰是我最大的優勢,因為在我這里,數據和程序表示的方式是一致的,都是list,比如這一段簡單的循環。”
(loop?for?x?in?'(1?2?3?4?5)do?(print?x)?)大家一看,果然如此,這代碼(loop函數)是用括號括起來的一個List, 這數據(1 2 3 4 5)也是一個List。
Lisp說:“List的好處就是天然可以和AST對應,這就方便宏來操作了。”
開發語言的語言
JavaScript說:“我還是看不出有什么用?”
Lisp接著說:“正是由于程序可以當做數據來處理,程序員可以無限地擴充Lisp,把Lisp變成他們所在領域的語言,使用這個領域特定的語言來編程,那簡直是如虎添翼,例如這個例子,通過擴展Lisp,? ?Lisp和SQL語言完美地融合了。 ”
(select?[age]?:from?[employee]?:where?[>?[salary]?50000])“再比如說, 在座的各位大都支持面向對象編程,對我來說,在我這里實現OOP也是小菜一碟,比如Common Lisp中的CLOS,就是用宏實現的OOP操作集。”
大家都表示很好奇, Lisp就展示了幾行代碼:
定義一個叫Person的類
(defclass?person?()((name?:accessor?person-name:initarg?:name)(age?:accessor?person-age:initarg?:age)))創建一個person對象
(setf?p?(make-instance?'person?:name?"andy"?:age?10))訪問對象的屬性
(print?(person-name?p))看到這里,大家都自愧弗如了, 這Lisp真有狂的資本啊。?
C 語言說到:“看來你Lisp是用來開發其他語言的語言啊!”
Lisp笑道:“這句話不錯,在我這里,語言和程序之間的界限是非常模糊的。”
最后的反擊
C語言問了最后一個問題:“既然你這么牛? 為什么用的人這么少?”
Lisp站起身來,嘆了一口氣:“有人說學起來門檻太高;有人說靈活與強大是一把雙刃劍,每個人都能造屬于自己的領域特定語言,讓別人難以理解和維護;還有人說Lisp方言很多,社區分裂,沒有統一的庫讓新手學習使用。 誰知道呢?”
說完Lisp便離開了,只留下一個滿是括號的背影。
總結
以上是生活随笔為你收集整理的为什么“无人问津”的Lisp可以这么狂?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Istio,灰度发布从未如此轻松!!!
- 下一篇: 如何发现 Redis 热点 Key ,解