不管在學術圈還是在工業界,總有很多人過度的關心所謂「程式的正確性」,有些甚至到了戰戰兢兢,捨本逐末的地步。下面舉幾個例子:
100%可靠的**,這是多麼完美的理想!可是到最後你發現,天天念叨著要「正確性」,「可靠性」的人,幾乎總是眼高手低,說的比做的多。自己沒寫出什麼解決實際問題的**,倒是很喜歡對別人的「**質量」評頭論足。這些人自己的**往往複雜不堪,喜歡使用各種看似高深的奇技淫巧,用以保證所謂「正確」。他們的**被很多所謂「測試工具」和「型別系統」捆住手腳,卻仍然bug百出。到後來你逐漸發現,對「正確性」的戰戰兢兢,其實是這些人不解決手頭問題的藉口。
這些人其實不明白乙個重要的道理:你得先寫出程式,才能開始談它的正確性。看乙個程式好不好,最重要的標準,是看它能否有效地解決問題,而不是它是否正確。如果你的程式沒有解決問題,或者解決了錯誤的問題,或者雖然解決問題但卻非常難用,那麼這程式再怎麼正確,再怎麼可靠,都不是好的程式。
正確不等於簡單,不等於優雅,不等於高效。乙個不簡單,不優雅,效率低的程式,就算你費盡周折證明了它的正確,它仍然不會很好的工作。這就像你得先有了房子,才能開始要求房子是安全的。想想吧,如果乙個沒有房子的流浪漢,路過一座沒有人住的房子,他會因為這房子「不是100%安全」,而繼續在野外風餐露宿嗎?寫出**就像有了房子,而**的正確性,就像房子的安全性。寫出可以解決問題的程式,永遠是第一位的。而這個程式的正確性,不管它如何的重要,永遠是第二位的。對程式的正確性的強調,永遠不應該高於寫出程式本身。
每當談起這個問題,我就喜歡打乙個比方:如果「黎曼猜想」被王垠證明出來了,它會改名叫「王垠定理」嗎?當然不會。它會被叫做「黎曼定理」!這是因為,無論乙個人多麼聰明多麼厲害,就算他能夠證明出黎曼猜想,但這個猜想並不是他最先想出來的。如果黎曼沒有提出這個猜想,你根本不會想到它,又何談證明呢?所以我喜歡說,一流的數學家提出猜想,二流的數學家證明別人的猜想。同樣的道理,寫出解決問題的**的人,比起那些去證明(測試)他的**正確性的人,永遠是更重要的。因為如果他沒寫出這段**,你連要證明(測試)什麼都不知道!
話說回來,雖然程式的正確性相對於解決問題,處於相對次要的地位,然而它確實是不可忽視的。但這並不等於天天鼓吹要「測試」,要「形式化證明」,就可以提高程式的正確性。
如果你深入研究過程式的邏輯推導就會知道,測試和形式化證明的能力都是非常有限的。測試只能測試到最常用的情況,而無法覆蓋所有的情況。別被所謂「測試覆蓋」(test coverage)給欺騙了。一行**被測試覆蓋而沒有出錯,並不等於在那裡不會出錯。一行**是否出錯,取決於在它執行之前所經過的所有條件。這些條件的數量是組合**關係,基本上沒有測試能夠覆蓋所有這些前提條件。
形式化方法對於非常簡單直接的程式是有效的,然而一旦程式稍微大點,形式化方法就寸步難行。你也許沒有想到,你可以用非常少的**,寫出collatz conjecture這樣至今沒人證明出來的數學猜想。實際使用中的**,比這種數學猜想要複雜不知道多少倍。你要用形式化方法去證明所有的**,基本上等於你永遠也沒法完成專案。
那麼提高程式正確性最有效的方法是什麼呢?在我看來,最有效的方法莫過於對**反覆琢磨推敲,讓它變得簡單,直觀,直到你一眼就可以看得出它不可能有問題。
王垠系列 一種新的作業系統設計
我一直在試圖利用程式語言的設計原理,設計一種超越 unix 哲學 的作業系統。這裡是我的設想 我曾經以為我是第乙個想到這個做法的人。可是調查之後發現,很多人早就已經做出了類似的系統。lisp machine 似乎是其中最接近的乙個。oberon 是另外乙個。ibm system 38 是類似系統裡面...
王垠推薦的一些Linux工具
shell bash。它結合了 csh 和 ksh 的優點,並且有 readline 功能,你可以隨意繫結自己的鍵盤。程式開發 gcc,make,ld,scheme48,j2sdk,perl,python,tcl tk 幻燈工具 latex,context 影象處理 imagemagick。其中的 ...
看了王垠的文章《對Rust語言的分析》
一開始我也看了一點點rust,可能是我這個人對這種語言就是看不懂,我好像就只對c系的語言比較有親和力,然後在知乎看到這麼一段話 這個問題類似於重複繫結變數和型別推導的問題,屬於一種 使用者體驗設計 問題。無論如何,編譯器都很容易實現,然而不同樣式的 對於人類閱讀的工作量,是很不一樣的。很多時候最省人...