怎樣看王垠的《談談Parser》?
王垠的博文鏈接:
談談Parser
演算法的發明要看背景。以前內存才幾個KB,所以這些SLR啊LL什麼的還是有用的。現在統統上GLR就可以了,多花幾個M誰在乎啊。就像是C++那樣的到處都可以寫出歧義的語法,GLR最多給你產生出在局部帶多個解的AST,然後你後面的pass去挑一個對的出來就可以了。
所以已經沒什麼好研究的了,大家都在干別的事情了。想寫一個什麼語言,只要你不在乎跟C#的編譯器一樣一秒編譯幾個M的代碼那麼快的話,挑選一個支持GLR的parser generator,然後隨便寫寫前端就搞定了。後端用.net或者LLVM,根本用不著自己手寫parser。
不過王垠有一點不好,因為他從來不試圖去完整的實現一個需求,總是留下很多「corner case」沒有做,所以覺得好像什麼都很簡單。事實上在21世紀的軟體工程裡面,只要你去試圖實現所有corner case,你是有可能發現當初想的那個設計完全沒有用的。搞研究的人就是喜歡講「ideally」。
以前我也覺得王垠跟他自己說的一樣很牛逼(他是很牛逼,但是沒有吹的那麼牛逼,哈哈哈),看過他一篇文章說他三下五除二就搞定了Haskell用的Hindley-Milner類型系統的類型推導演算法。我以前也寫過,覺得要搞出一個能用的語言(至少得可以用這個語言來寫parser combinator對吧,不然算什麼函數式語言),寫這個類型推導的演算法到處都是坑,於是我就問他,你到底是怎麼實現多個函數互相遞歸的類型推導的?我當初用了blah blah blah的技巧,寫了那麼多test case來窮舉那些奇怪的情況,修了那麼多bug,才完全搞定的,中間還搞出很多死遞歸,怎麼想都不可能三兩下寫出來啊。
結合王垠以前說測試就是懦夫(非原話)的說法,再熟悉的人默寫qsort都有可能寫錯呢,還記得當初說幾乎沒人能一次性寫對二分搜索的那篇論文嗎?
他說:我沒有支持這種遞歸。
卧槽。「我知道我的JavaScript和C++的parser有些corner case沒有cover,但是我真的不care,如果我真的有需求,要把它們做完,也就是需要簡單的修修補補而已。最重要的是,我掌握了最通用的技巧,它們已經能處理絕大部分的情況。」
我想起一幅很老的漫畫,好像標題叫「怎樣畫一匹馬」
其他的部分我是贊同的。其實我們編譯器開發,很多時間都是在解決Corner Case,或許這就是研究者和實際工程的一些區別吧。
既然王先生說寫出了 js 的 parser,那他能不能說明下分號插補他是怎麼處理的。別以為 Corner Case 就好做,有時候這些東西才要人老命。
關於Parser的觀點有一部分是對的,王垠的水平不評論,但是某些大V強行那HM類型系統裝逼也是醉了。
HM演算法算是最沒有corner case的演算法,推導的規則全部是已知的,只要實現對應的規則就好。遞歸函數轉化為求函數的不動點,設遞歸的函數類型為f,推導出來的不動點的類型為f-&>t, 然後把兩邊的f和t歸一化(Unification)就可以得到遞歸函數的類型。Corner case某些情況下的確很要命,但是工程不尊重學術的結論生生自己無端造出來許多corner cases可是一點說服力都沒有。想到個事,文中提到R. Kent Dybvig,他的學生Michael D. Adams,還在POPL 13發了篇Parsing相關的文章(Principled Parsing for Indentation-Sensitive Languages)。。。。
PL Parsing相關研究確實已經非常非常地少了,自然語言那邊不了解;
關於最後說的『PL這個領域,真的是高於編譯器領域「:
Compiler尤其是FP語言的compiling也需要很多理論的東西,CPS/ANF/..就不說了,可以看看POPL 14上的Cardinality analysis, Modular, Higher-Order Cardinality Analysis in Theory and Practice,又比如很理想化的supercompilation,optimal beta-reducation.... 這兩個領域並不衝突,Andrew Appeal, Simon Peyton Jones。。誰敢說他們的PL理論不好,,命令式、OO的C/Java之類的也不簡單,譬如經典的Pointer analysis,研究幾十年了還有人在做。。。 當然不論語言,激進、理想的優化都依賴於成熟的analysis, transformation技術(實際用的其實都不怎麼成熟,乃至根本不用)黑王垠 在 知乎 已經是一種政治正確的表現了。
那一段臟活丟給碼奴的想法還是很不錯的,不過我是覺得30多的老人還要寫這種文章澄清自己的想法有點憋屈……
但其實優化和機器碼生成也是雜活呀……- 很符合yin wang一慣的民科文風,全篇充斥著自我吹捧和對他人工作的貶低。
- 他說的也不是沒有道理,的確parser是很流水線的東西,但是什麼github約架parser這種事情應該也就溫兆倫這種水平的能做(好吧去掉趙)
- Corner case 是很要命,但是拿出來吹捧就不對啦。事實上mutually recursive function不就是個fix point 的問題嘛,人家壓根沒放眼裡。
1. 不管你們怎麼噴,王垠對大學編譯原理課的吐槽是真的一針見血。
2. 文人相輕,大家熱鬧看夠了就散了吧,沒必要挖苦別人。
3. 不知你們讀過他的那篇關於一場車禍的文章沒有,我覺得我從這篇文章讀到的是一個有社會責任感,能看到問題癥結的王垠。我覺得噴他的很多人里並沒有這些值得我讚歎的品質。
4. 人都會遇到自己能看見卻無力解決的問題。看到了,雖然不一定能以當前的能力去解決問題,但說出來總歸是好的,好歹比那些看著別人往坑裡走也不吭聲的人強...
5. 記得魯迅曾經評價屈原是「不得幫忙的不平」,王垠又何嘗不是呢。雖然先生的原意是諷刺屈原的,但我覺得因「不得幫忙」而「不平」的人,是真性情的人,至少比「不得利益而不平」的人好得多...
6. 最後雞湯一下。上帝把每個人的缺點裝進一個口袋掛在了每個人的背後,於是我們每個人總是先看到別人的缺點。
共勉
我認真讀了這篇文章,有學到不少東西。感謝王先生。也許王垠在某些方面比不上輪子哥或winter,但是我很肯定:他至少比我厲害1024倍。
他所推崇的理念,簡單就是美。他了解計算機的運轉本質,他嘗試從設計的角度,告訴你一個好的parser應該如何如何…這其實是一種突破…
他都說了是在扯淡了, 你還想怎麼看..."當然我在扯淡"
腦補一下, 你在這裡煞有介事的blablablabla, 那邊廂王垠抿嘴一笑, 輕撫狗頭, "我這是在扯淡..."
吐血而亡.文章里的一些觀點我是贊同,例如一些類型檢查和語義分析應該放在parser之後,其實我所在的小組目前接手的一個c++靜態分析工具的parser就存在這個問題:
在parsing階段就進行類型檢查,實際上,一些類型的定義和聲明是在頭文件裡面的,很多c工程都是如此,而提前進行類型檢查就意味著需要對原始代碼進行預處理,然而預處理之後的代碼就會發生重大變化,這樣又不利於我們這些parser後端的開發人員去將缺陷警報定位到原始代碼中(例如一個#define MAX 1024就可以把三位元組的MAX轉成4位元組的「1024」,這確實是給後端的工作造成了不少問題)。
PS:最近老闆又讓增加一個工程級的文件依賴分析,想想,都做了預處理的文件的AST,再跑回到被include進來的header file中進行定位,怎麼都覺得有點兒重複分析的感覺。。。→_→如果不考慮corner case 其實寫一個語言真的很簡單,我們可以看看具體的對比案例。
先是lisp的原型和產品對比
Contents ? Build Your Own Lisp
在這裡我們可以看到有一個lisp編譯器的範例代碼,壓縮後只有40k,包括makefile只有20個文件。那麼考慮了corner case之後的lisp編譯器有多少代碼呢?
可以看看編譯到jvm的clojure的項目
clojure/clojure · GitHub整個master.zip 是800k,src下有237個文件,也就是說複雜度上基本為原型的10倍。代碼行對比也類似Build Your Own Lisp-------------------------------------------------------------------------------
Language files blank comment code-------------------------------------------------------------------------------C 16 1538 505 5206C/C++ Header 1 70 44 194make 1 6 0 19-------------------------------------------------------------------------------SUM: 18 1614 549 5419-------------------------------------------------------------------------------clojure
-------------------------------------------------------------------------------
Language files blank comment code-------------------------------------------------------------------------------Java 167 6311 13011 39023Clojure 44 2542 935 16584HTML 4 24 76 135XML 2 0 0 81-------------------------------------------------------------------------------SUM: 217 8877 14022 55823-------------------------------------------------------------------------------在看看haskell的原型和產品對比。
sdiehl/write-you-a-haskell · GitHub這個項目裡面一共有74個hs文件
-------------------------------------------------------------------------------Language files blank comment code-------------------------------------------------------------------------------Haskell 74 1225 367 4368-------------------------------------------------------------------------------SUM: 74 1225 367 4368-------------------------------------------------------------------------------而真實的編譯器呢?
ghc/ghc · GitHub有5800多個hs文件,從文件數量看多了70倍。-------------------------------------------------------------------------------
Language files blank comment code-------------------------------------------------------------------------------Haskell 5570 80108 110984 290721C 1 12 14 38CSS 1 1 0 4-------------------------------------------------------------------------------SUM: 5572 80121 110998 290763-------------------------------------------------------------------------------從代碼行來看也有66倍左右的差距。ps我只統計了ghc下的hs代碼,
對於王垠本人,我覺得可能不是適合用「Talk is cheap, show me the code!」,但是真走學術,那我倒是想說「Talk is cheap, show me the paper!」。
也沒有聽說他有什麼重要的論文可以讓大家學習的啊。原文說:
能寫parser並不是什麼了不起的事情,其實它是非常苦逼,真正的程序語言和編譯器專家根本不屑於做的事情。那就用antlr好了,說半天幹嘛呢???我真的覺得,寫一個專用的analyzer沒什麼意義,除了練手,或者語法確實足夠奇怪╭( ̄▽ ̄)╮輪子是因為躺槍了,之前他用c++11寫了parser證明自己很牛逼。 卧槽~~~~~~~~~~~~~
報告老師,本文的中心論點:parser只是一個簡單的環節,根本不重要,因為世界上最好的語言 scheme 只需要簡單的技術就能parser,而編譯器後端的優化則重要得多。
其實這篇文章說的有點道理。不知道王垠是怎麼看DSL的,parser在DSL的工程應用上很有用。跟他說的那樣,代碼的本質就是邏輯結構。但是能解決實際問題的代碼,其邏輯結構要適合實際問題的內在邏輯結構。所以會有用DSL這種二次創造的東西。
王垠google實習的領導對他的評價、清華退學時老師對他說的話、美國博士導師對他的評價等等都讓我覺得他太牛,一般人根本沒有能力評價他,難道那些評價是王自己杜撰的?還是那幾個近距離接觸他的人腦子進水?
推薦閱讀:
※如何評價王垠的《編程的宗派》?
※怎麼看待王垠對 Haskell 的評價?
※如何看待王垠的 《對 Rust 語言的分析》?
※如何評價王垠新博文《我看自動駕駛技術》?
※曾老師如何看待除了垠神之外其他三大編程天王?
