標籤:

理論上最好的編程語言: 起點動機篇

人相比其他動物而言,最厲害的不在於使用工具,而在於發明製造工具。

語言就是人類製造的工具之一,人將對世界的探索與歸納,形成文字、圖畫以及各種媒體資料,流傳於世。而數理邏輯則是用語言定義的運算規則,是嚴密分析真假的工具,最初在我們腦中存在,後來則在我們製造的機器中存在。

工業革命,以蒸汽機為開端,開啟了用熱機自動驅動機器造物的時代。

人造物,人用機器造物,人造機器造物(自動化),人造機器造機器造物。

而這些造物最後還是服務於人,擴展人的能力,遵從人的慾望。在人類智慧與慾望的交互推動之下,社會從農業需要發展出工業,從工業需要發展出了信息技術產業,並通過編譯器與編程語言的發明,造就了諸多需要通過編程解決問題的工作崗位。

於是,編程技巧與術語也就被這些工作需求推動著,演進著。其中有一個術語,就是"元編程"。

元編程,即是用程序生成程序的意思。實際上,它的思想開端很早,就像前面所說的,用程序寫程序的思想,和用工具造工具,以及用機器造機器的思想是一致的。但是這一切還是要歸結到 「服務於人」 的點上,那麼,元編程於人類的意義何在?

答案是「最短代碼」。(如果脫離"代碼"這種形式,那麼其實可以替換為"達到目的所需的開銷")

也就是說我們之所以用元編程,目的是為了減少編程的代碼量,而程序代碼量的減少,一方面有助於程序員記憶演算法關鍵,但另一方面也會導致很多與演算法本身無關僅僅是為了簡化代碼而抽象出來的抽象棧(這反而會造成理解困難)。

所以,實際上,我們需要的是簡短又條理清晰易懂的代碼。

為此,做出過很多探索與發明,從 fortran 到 lisp 到 C,再到後來發明的很多 「高級」 編程語言,都是這種需求的產物。然而這些產物在解決最初的一些問題後,給初學者帶來了選擇上的混亂,畢竟通曉一門編程語言所需的成本可不低,背後往往是一套「生態系統」。所以很多想操縱時代機器的編程初學者都會問一個問題:「什麼是最好的編程語言?」

編程「老司機」會告訴你們:不存在的,都是根據需要選工具,也即根據開發需求選擇對應最有效的編程語言。

但是,這個"不存在"是由人類造成的,是「社會實際」中的不存在。那麼在理論上,它有沒有可能存在?

編程語言出現的歷史價值

最初的編程方式,確實是用 "101010……" 的二進位串來實現的(具體地說是「打孔紙帶」),但這種實現方式麻煩且容易出錯,後來的編程方式就改成了彙編,用一些人類易讀易懂的字元串來替代二進位流。

一般來說,一個硬體晶元的彙編指令集是由生產該硬體晶元的公司提供的,不同公司有不同的硬體,不同硬體有不同的指令集,而在這些不同硬體晶元上實現的程序演算法思想卻常常是一樣的。

這就意味著,同一個演算法要針對不同的指令集合寫出不一樣的彙編代碼。人工去做這件事,有極大的重複冗餘。

類似 fortran、lisp 和 C 等編程語言的發明,除了帶給人們良好的程序讀寫體驗,實際上還建立了一個跨硬體指令集的邏輯平台。(通過給不同指令集合建立該語言的編譯器),實現 C++ 所宣稱的 "write once, compile everywhere" 或者 java 語言宣稱的 "write once, run everywhere",以此消除了上面提到的重複冗餘。

不過,自從 fortran 發明以來,人類發明的各式各樣的編程語言以及 DSL(Domain Specific Language),反而帶來了分裂,以及學習上的冗餘。雖然在實際操作中,總有高手能將不同的語言膠合起來使用,但這樣也帶來不少系統維護上的麻煩。並且,不同編程語言各有各的優缺點。將它們結合起來使用很多時候只是工程需求所逼,用於克服各自的應用短板。至於編程語言自身的「一些問題」,並不能被另一種編程語言克服。

這裡我舉幾個典型的編程語言,來說說它們的優點以及它們自身的「一些問題」。

Unix 與 C —— 系統與系統欽定的語言

C 語言在當今計算機界能有如此地位的原因,很大程度上源於它是 Unix 系統欽定的語言(據說還有 C 原版的語法手冊非常簡單的原因),同時由於 Unix 系統進入了 IEEE 標準,進而指導了 linux 系統的發明,從而穩固了它在編程語言界的地位。

Unix 系統,不考慮它的圖形界面的話,是由 C 語言寫的程序以及它們的配置文件,還有 shell 腳本組成的。

人工去操作沒有圖形界面的 Unix 系統,必須通過 shell。

如果要自動化一些任務,除了寫 C 代碼並將它編譯成二進位程序進行自動化以外,就是使用 shell 編寫 shell 腳本來實現。(雖然現在有了很多 REPL(read evaluate print loop) 語言,如 python、ruby 以及 javascript 等等,但實際上它們的意義是 C 和 Shell 的混合)

Unix 系統里,不同程序的配置都是通過文件實現的,而這些文件根據程序的不同,有各自的格式。

這種語言上的二分性,以及配置文件格式上的多樣性,給 Unix 系統帶來了「繁榮」。

雖然這種「繁榮」在外行人看來,是令人望而生畏的混亂。

一個系統欽定了這個系統主要使用的編程語言,這並不只發生在 Unix 與 C 的身上,同樣我們能看到:

web browser 欽定了 javascript;

android 欽定了 java (雖然 java 是在 android 系統之前發明的);

Matlab 與 matlab 語言、Mathematica 與 mathematica 語言、emacs 與 emacs lisp 以及 blender 與 python 語言等等。

雖然有些不是強綁定的,但一個指定編程語言的系統還是繁榮了這門編程語言。這也是編程語言社區分裂的根源——它們所應用的領域不一樣,進而佔據了不同的系統。

這裡,C 語言的缺點,我個人認為並不是指針。 C 的缺點是相對於 lisp 這種編程語言而言的(lisp 的優點正是 C 語言的短板)。同時,C 沒有 REPL,但這個短板由各種 shell 補上——譬如 bash, zsh 等等。

lisp 與 lisp machine

lisp 的優點之一在於括弧與前綴表達式。這兩樣東西極大地減少了編程語言的歧義(不用背優先順序了)。

lisp 的優點之二在於它的宏的強大——這是 C 語言的預處理器所不能比擬的。

lisp 的失誤根源在於語法表達上的過分自由,以及脫離硬體本身的語法描述。前者造成 lisp 社區的分裂,後者造成 lisp 程序的機器效率低下(這直接影響了用戶體驗)。

lisp 還有一個問題,那便是用符號代換系統的輸入輸出,這會讓數據流向變得非常詭異,使得代碼的可讀性變差(是的, lisp 的可讀性變差,在我看來並不是因為括弧)。當然,這個問題,大部分編程語言都有。

Haskell、 ML 系語言等函數式編程

函數式編程最大的優勢在於語句簡練以及可擴展的並行性,據說還有數學以及邏輯上的清晰性。

但我認為函數式編程有它的短板。

雖然沒採用 lisp 的括弧和前綴表達也算是 Haskell 和 ML 系語言的短板之一,但最重要的是,我們實際的計算機硬體,是一套有記憶(存儲)的系統。

所以在這個系統里構建的"面對相同的輸入總是能給出相同輸出"的純函數能起到的作用只能是有限的。

而且函數本就應該"面對相同的輸入總是能給出相同輸出","純函數"這種說法就有混淆概念之嫌。不過這大概是因為一般編程里的「function」並不像數學裡的函數——比如 C 語言的 function 輸入中就有指針,數學概念里可沒有。

另外,"減少全局變數能提高代碼的可讀性與清晰性"這種概述錯誤地理解了編程工作複雜性的真正來源。

編程的複雜性來自於兩個方面: 人類想完成的事務(思想和演算法)和用於完成事務的機器(現實硬體)。

這裡先不討論人類的思想有多複雜,單就一個操作系統(狀態機)中的多個進程(子狀態機)運行在單一的個人電腦這個硬體(最終狀態機)上時,要處理的問題就非常多——多個狀態機共用處理單元,分配內存,共用匯流排,共用電腦顯示屏(考慮窗口的話就有很多花式)等等,這些都需要調度,且有各自的複雜性,其中涉及各種數學演算法……

是的,這裡我談到了狀態機(state machine)。一個有記憶的系統面對相同的輸入可能給出不同的輸出,正是因為這個系統有記憶(狀態),是個狀態機。這種計算形式在實際中有非常廣泛的應用。

而 Haskell 處理這種計算形式的方式,我並不苟同。

CPLD 和 FPGA 上的硬體描述語言

verilog HDL 語言和 VHDL 語言對電子系出生的工程師來說都不陌生,它們才是能做到真正(物理)並行計算的語言。但實際上,HDL 語言存在過分描述硬體細節(譬如高阻態等電學性質的描述)的問題。並且,這兩種語言都沒有將 CPU 作為編譯目標。而且,它們的開發者們似乎也沒有將 CPU 作為編譯目標的計劃。

對我而言,由於喜歡 lisp 的括弧帶來的優先順序簡化,所以對 verilog HDL 和 VHDL 的語法也頗有微詞。

於此,開始設計 OOWA(理論上)

在此我想把這種理論上探討的「最好的編程語言」命名為 OOWA,這是英文 "One programming language One system With All hardware" 的縮寫,意為在所有硬體上的一個系統一個編程語言。

這可能嗎?人類文明延續了幾千年,也沒有出現一個統一所有人類語言的人類語言,巴別塔也不過只是《聖經》中的一個故事。

「行成於思,毀於隨」

於此,我只想從「人造物」的角度出發,依據「用文本控制機器」的需求,按照「適用於所有硬體設備」的方式,結合編程語言的歷史,探討這種編程語言的設計。

根據 When we share, everyone wins - Creative Commons 網站的協議,本文

署名-非商業性使用-相同方式共享

CC BY-NC-SA

下篇:

王博文:理論上最好的編程語言: 哲學基礎篇?

zhuanlan.zhihu.com圖標
推薦閱讀:

中文編程目前面臨的難題是什麼,你有哪些建議?
如何編寫優質的API文檔?
如何進行系統性的編程學習?
大數據時代對編程有什麼影響?

TAG:編程語言 |