Lisp語言是怎么來的–LISP 和 AI 的青梅竹馬
LISP 語言的歷史和一些番外的八卦和有趣的逸事,其實值得花一本書講。 我打算用三篇文章扼要的介紹一下 LISP 的早期歷史。 講 LISP, 躲不過要講 AI (人工智能)的,所以干脆我就先八卦八卦他們的青梅竹馬好了。
翻開任何一本介紹各種編程語言的書,都會毫無驚奇的發現,每每說到 LISP, 通常的話就是”LISP 是適合人工智能(AI)的語言”。我不知道讀者讀到這句話的時候是怎么理解的,但是我剛上大學的時候,自以為懂了一點 LISP 和一點人工智能的時候, 猛然看到這句話,打死我也不覺得”適合”。 即使后來我看了 SICP 很多遍, 也難以想象為什么它就 “適合” 了, 難道 LISP 真的能做 C不能做的事情么? 難道僅僅是因為 John McCarthy 這樣的神人既是 AI 之父, 又是 LISP 之父, 所以 AI 和 LISP兄妹兩個就一定是很般配? 計算機科學家又不是上帝,創造個亞當夏娃讓他們沒事很般配干啥? 既然本是同根生這樣的說法是不能讓人信服的,那么到底這句話的依據在哪里呢? 我也是后來看 AI 文獻, 看當年的人工智能的研究情況,再結合當年人工智能研究的指導思想,當年的研究者可用的語言等歷史背景,才完全理解“適合” 這兩個自的。 所以,這篇既是八卦,也是我的心得筆記。我們一起穿越到 LISP 和 AI的童年時代。 雖然他們現在看上去沒什么緊密聯系, 他們小時候真的是青梅竹馬的親密玩伴呢!
讓機器擁有智能, 是人長久的夢想, 因為這樣機器就可以聰明的替代人類完成一些任務。二戰中高速電子計算機的出現使得這個夢想更加近了一步。二戰后,計算機也不被完全軍用了,精英科學家也不要繼續制造原子彈了,所以,一下子既有資源也有大腦來研究 “智能機器”這種神奇的東西了。 我們可以隨便舉出當年研究繁盛的例子: 維納在 1948年發表了<控制論>, 副標題叫做 <動物和機器的控制和通信>, 其中講了生物和機器的反饋,講了腦的行為。創立信息論的大師香農在 1949 年提出了可以下棋的機器,也就是面向特定領域的智能機器。同時,1949年, 加拿大著名的神經科學家 DonaldHebb 發表了“行為的組織”,開創了神經網絡的研究; 圖靈在 1950年發表了著名的題為“計算的機器和智能”的文章,提出了著名的圖靈測試。如此多的學科被創立,如此多的學科創始人在關心智能機器,可見當時的確是這方面研究的黃金時期。
二戰結束十年后, 也就是 1956 年, 研究智能機器的這些研究者,都隱隱覺得自己研究的東西是一個新玩意,雖然和數學,生物,電子都有關系, 但和傳統的數學,生物,電子或者腦科學都不一樣,因此,另立一個新招牌成了一個必然的趨勢。John McCarthy 同學就趁著 1956 年的這個暑假, 在 Dortmouth大學(當年也是美國計算機科學發展的圣地之一, 比如說, 它是 BASIC 語言發源地), 和香農,Minsky等其他人(這幫人當年還都是年輕人),一起開了個會, 提出了一個很酷的詞, 叫做 Artificial Intelligence,算是人工智能這個學科正式成立。 因為 AI 是研究智能的機器, 學科一成立, 就必然有兩個重要的問題要回答,一是你怎么表示這個世界,二是計算機怎么能基于這個世界的知識得出智能。 第一點用行話說就是”知識表示”的模型,第二點用行話說就是“智能的計算模型”。 別看這兩個問題的不起眼, 就因為當時的研究者對兩個看上去很細微的問題的回答, 直接造就了 LISP 和AI 的一段情緣。
我們各表一支。 先說怎么表示知識的問題。 AI 研究和普通的編程不一樣的地方在于, AI 的輸入數據通常非常多樣化,而且沒有固定格式。比如一道要求解的數學題,一段要翻譯成中文的英文,一個待解的 sodoku 謎題,或者一個待識別的人臉圖片。 所有的這些,都需要先通過一個叫做“知識表示”的學科,表達成計算機能夠處理的數據格式。自然,計算機科學家想用一種統一的數據格式表示需要處理多種多樣的現實對象,這樣, 就自然的要求設計一個強大的,靈活的數據格式。 這個數據格式,就是鏈表。
這里我就不自量力的憑我有限的學識, 追尋一下為啥鏈表正好成為理想的數據結構的邏輯線。我想,讀過 SICP的讀者應該對鏈表的靈活性深有感觸。為了分析鏈表的長處,我們不妨把他和同時代的其他數據結構來做一比較。如我在前面的一個系列所說,當時的數據結構很有限,所以我們不妨比較一下鏈表和同時代的另一個最廣泛使用的數據結構-數組-的優劣。我們都知道,數組和鏈表都是線性數據結構,兩者各有千秋,而 FORTRAN 基本上是圍繞數組建立的,LISP則是圍繞鏈表實現的。通過研究下棋,幾何題等 AI 問題的表示,我們的讀者不難發現, AI研究關心于符號和邏輯計算遠大于數值計算,比如下棋,就很難抽象成一個基于純數字的計算問題。 這樣,只能存數字的數組就顯得不適合。當然我們可以把數組擴展一下,讓這些數組元素也可以存符號。不過即使這樣,數組也不能做到存儲不同結構的數據。比方說棋類中,車馬炮各有各自的規則,存儲這些規則需要的結構和單元大小都不一樣,所以我們需要一個存儲異構數據單元的模塊,而不是讓每個單元格的結構一樣。 加上在AI 中,一些數據需要隨時增加和修改的。比如國際象棋里,兵第一步能走兩步,到底部又能變成皇后等等,這就需要兵的規則能夠隨時修改,增加,刪除和改變。其他問題也有類似的要求,所有的這些,都需要放開數組維度大小一樣的約束,允許動態增加和減少某一維度的大小,或者動態高效的增加刪除數組元素。而一旦放開了單元格要同構和能隨時增加和刪除這樣兩個約束,數組其實就不再是數組了,因為隨機訪問的特性基本上就丟失了,數組就自然的變成了鏈表,要用鏈表的實現。
所以,用鏈表而不是數組來作為人工智能的統一的數據結構,固然有天才的靈機一動,也有現實需求的影響。當然,值得一提的是,在 CommonLISP 這樣一個更加面向實踐而不是科學研究是 LISP 版本中,數組又作為鏈表的補充,成了基本的數據結構,而 CommonLISP,也就能做圖像處理等和矩陣打交道的事情。這個事實更加說明,用什么樣的數據結構作為基本單元,都是由現實需求推動的。
當然,科學家光證明了列表能表示這些現實世界的問題還不夠, 還要能證明或者驗證額外的兩點才行,第一點是列表表示能夠充分的表示所有的人工智能問題,即列表結構的充分性。只有證明了這一點,我們才敢放心大膽的用鏈表,而不會擔心突然跳出一個問題鏈表表達不了;第二是人工智能的確能夠通過對列表的某種處理方法獲得,而不會擔心突然跳出一個人工智能問題,用現有的對鏈表的處理方法根本沒法實現。只有這兩個問題的回答是肯定的時候,列表處理才會成為人工智能的一部分。
對于這兩個問題,其實都并沒有一個確定的答案,而只是科學家的猜想,或者說是一種大家普遍接受的研究范式(paradigm)。 在 1976年, 當年構想 IPL, 也就是 LISP 前身的兩位神人 Alan Newell 和 Herbert Simon,終于以回憶歷史的方式寫了一篇文章。 在這篇文章中,他們哲學般的把當時的這個范式概括為: 一個物理符號系統對于一般智能行為是既充分又必要的( Aphysical symbol system has the necessary and sufficient means forgeneral intelligence action)。用大白話說就是,“智能必須依賴于某種符號演算系統,且基于符號演算系統也能夠衍生出智能”。在實踐中,如果你承認這個猜想,或者說這個范式,那你就承認了可以用符號演算來實現 AI。于是,這個猜想就讓當時幾乎所有的研究者,把寶押在了實現一個通用的符號演算系統上,因為假如我們制造出一個通用的基于符號演算的系統,我們就能用這個系統實現智能。
上面我們說過,鏈表的強大的表達能力對于這個符號演算系統來講是綽綽有余的了,所以我們只要關心如何實現符號演算,因為假如上面的猜想是對的,且鏈表已經能夠表示所有的符號, 那么我們的全部問題就變成了如何去構建這樣的符號演算系統。后面我們可以看到, LISP 通過函數式編程來完成了這些演算規則的構建。
這里,需要提請讀者注意的是, LISP 的全稱是 LISt Processing, 即列表處理,但實際上 LISP 是由兩種互相正交的哲學組合形成的, 一個是列表處理,另一個是函數式編程。 雖然在下面以后,我們會介紹 S-Expression這樣美妙的把兩者無縫結合在一起的形式,但是為了清晰我們的概念,我要強調一下列表處理和函數式編程是兩個正交的部分。實際上,我們完全可以用其他的不是函數的方式構建一個列表處理語言。在歷史上,早在 FORTRAN 出現之前,Alan Newell 和 Herbert Simon就用匯編實現了一個叫 IPL 的語言,而這個 IPL 語言就是面向過程的對列表處理的,而后,McCarthy 一開始也是用一系列的FORTRAN 子程序來做列表處理的。比如 LISP 里面的 CAR 操作,其全成實際上是 Content of the Addressportion of the Register,顧名思義,寄存器的地址單元內容,也即列表的第一個元素(和C表達數組的方式類似,這里寄存器中存著指向列表第一個元素的指針)。函數式的卻不以列表為基本數據單元的語言也很多,比如 Scala ,就是以對象為基本數據單元。 因此,函數式和列表處理是不一定要互相耦合的。那么,到底是什么原因使得 LISP 選擇函數式,這樣的選擇又為啥更加適合當時 AI 的研究呢, 我們下節將繼續介紹當時 AI 的研究范式,強弱AI 之間的辯論和函數式編程在當年 AI 研究上的優點。
上回我們說到 LISP 和 AI 很是青梅竹馬的時候,浮光掠影地說因為 LISP 的基本數據單元–”鏈表”在知識表示上的比較優勢。我們說, AI 要處理的數據結構和要刻畫的現實世界的模型很復雜,使得數組等其他簡單數據結構不能勝任,所以“鏈表”成了最佳的選擇。如果我們順著這樣的邏輯線往下看,似乎選擇 LISP 這個“列表處理的語言”似乎是理所當然的。 可是,這個原因并不充分。 因為 LISP語言可不僅僅是列表處理,還包括函數式編程等等其他。 反過來說,如果僅僅是列表處理對于 AI 至關重要的話,那么在 FORTRAN 和 Algol這些通用編程語言又非常普及的傳統語言里面寫一些關于列表處理的函數豈不是更加直觀和方便? 歸根結底,到底 LISP 還有什么其他奧妙呢?
當我們追尋函數式編程這條線索的時候,就會不可避免的觸及到 AI 的早期歷史。LISP 的特性,其實都是和當時 AI 的范式 (paradigm) 息息相關的。
AI 范式的演變
早在 McCarthy 這一代人提出 AI 之前,馮諾伊曼等人就開始研究什么是智能以及如何實現智能的問題了。所不同的是,他們更加偏重于研究大腦的內部工作機理,并且試圖通過在模擬大腦的工作機理,來實現智能。 這一學派的哲學很清晰:人類大腦是一個標準的智能體,我們只需要讓計算機模擬人的大腦的工作方式,計算機就有了和人類大腦一樣的智能了。對于這一派的研究者來說,他們相信大腦的結構和工作機理決定了智能,至于大腦是用腦細胞構成的,還是用電子電路模擬的,對于智能來說毫不重要。這方面的著名工作就是馮諾伊曼的《計算機和大腦》這篇論文。在這篇不算很學術的隨筆里面,他分析了人的大腦有多少個神經元,計算機有多少個晶體管,通過這些定量的比較來解釋計算機和人的大腦的差距。當時和馮諾伊曼齊名的另一個神童是開創控制論的維納。 他和馮諾伊曼一樣,兼通很多學科。和馮諾伊曼一樣,他職業是數學家,但是也精通如神經科學和腦科學等學科。一個顯然的例子就是在《控制論》這本書里面,維納對大腦和神經的分析比比皆是。這種對大腦和神經分析的傳統,從 Cajal (對,就是寫 Advice for a Young Investigator 的那個大神) 開始,一直延續到了后來 AI 中的聯接主義(主要研究神經網絡的一個人工智能學派)。
可是,從腦科學和認知科學的角度去分析智能在當時有一個非常大的局限: 腦神經解剖學本身不成熟。比方說,現如今腦科學家在分析腦功能的時候一般會借助于 fMRI和其他一些神經造影技術。這些技術可以做到實時觀測到腦中血氧分布,直接確定大腦在執行特定任務時候的活躍部分。當年的科學家則只能使用有限的幾種醫學成像技術,或者從血管攝影的角度研究大腦。 受限于當時的研究條件,當年的研究者很難直接觀測到腦神經的實時工作狀態,分析大腦的實時工作機理。因此,對腦的研究就很難做到非常深刻。 醫學研究條件的限制,加上當時電子學的發展和集成度遠遠不夠,用電子電路模擬大腦生成智能就顯得非常遙遠。因此,雖然這一派的思想超前,但是大部分的工作都不在于真正的用電子電路模擬大腦,而是在探索腦科學和神經科學本身,或者僅僅用電子電路模擬一些簡單的神經動力學行為和小規模神經網絡。正是因為連接主義在實現人工智能本身方面進展并不大,所以在AI領域中一直不是潮流的研究方向。上個世紀 80年代前成功實施的一些人工智能系統,極少是來自于連接主義學派的。直到80年代后隨著 BP 算法的重新發現,聯接主義才迎來了第二春。這時候,LISP 已經過完 20 歲生日了。所以,聯接主義 對 AI 領域使用的編程語言的選擇的影響并不算大。
符號主義
雖然聯接主義這一學派在當時不怎么流行,當年的 AI研究可是進行的如火如荼。這如火如荼的學派,采用的是另外一套方法,我們稱之為“符號主義學派”。符號主義學派的淵源,可以直接追溯到圖靈。圖靈在人工智能方面做過很多的研究,其中最為大家所知的就是“圖靈測試“了。有句俗話叫做“在網上,沒人知道你是一條狗”, 在這句話里,只要把“狗”換成“計算機”,就是簡單版的圖靈測試了。用個比較“潮”的比方,圖靈測試就是讓一臺計算機或者一個真實的人(又叫評委)在網上交流,然后讓這個評委猜測和他交談的究竟是人還是計算機。如果這位評委也不能分辨談話的對方到底是人還是計算機的話,我們就認為這個計算機已經足以“以假亂真”,擁有“和人類一樣的智能”了,也就是通過“圖靈測試了”。
在很長一段時間里,圖靈測試一直是人工智能研究的圣杯(holy grail)。 也就是說,通過”圖靈測試“ 成了人工智能研究的終極目標。那么,自然的,最最直接的通過圖靈測試的方法不是讓計算機和人腦一樣思考,而是只要能夠讓計算機處理對話中用到的的單詞,句子和符號,并且在對話中能夠和人一樣的操縱這些單詞和符號,計算機就有很大的希望通過圖靈測試。從最極端的情況來看,計算機甚至都不需要去“理解”這些句子的含義,都有可能通過圖靈測試。 [具體細節可以閱讀 Wikipedia 上的“Chinese Room(中文房間)”條目]。 有一個開源的聊天機器人,叫做 A.L.I.C.E.,就把上面我們說的“只要能夠處理和操縱符號,就有可能通過圖靈測試”發揮到了近乎極致。這個聊天機器人在圖靈測試比賽中已經多次騙過人類評委,到了非常“智能”幾乎能以假亂真的地步。可是,就是這樣一個離通過圖靈測試很近的機器人,其基本結構卻簡單到了我們都不能想像的地步:A.L.I.C.E. 的數據庫里面有一條一條的規則,這些規則規定了她看到你說什么的時候她說什么。唯一有點“智能”的地方,就是有些規則不光取決于你這句話,還取決于你的上一句話。[比如日常對話中我們先問“你喜歡看電影么?”,接著再問“什么類型的?”,這時候就需要前一句話推出這個問題是“(喜歡)什么類型的(電影)”]。“中文房間”的例子,和 A.L.I.C.E.機器人如此簡單的結構,都出人意料的顯示出,即使計算機擁有了對符號的操作能力,通過了圖靈測試,它也未必是是“有智能”的。可惜這句話只是我的馬后炮而已,在 AI 發展的早期,因為圖靈測試的拉動,聯接主義的相對弱勢和符號主義的繁盛,都把全世界的 AI研究往一個方向拽,這個方向,很自然的,就是“符號處理”。
符號處理和LISP 補充
其實上一篇我們已經提到了,Alan Newell 和 Herbert Simon認為對符號演算系統就可以衍生出智能,所以上面的文字,算是對符號主義這個 paradigm 做一個歷史的小注解。 當我們把 LISP放到這段歷史中,就會自然的想到, 什么語言適合人工智能的問題,就變成了“什么語言能做符號處理”。這個問題的答案,讀者也都猜到了,就是 LISP。
符號處理在 LISP 里面的長處前文我已經介紹過一些了,這里我們可以再補充幾點零碎的。LISP 里有一個大家都知道的統一表示程序和數據的方法,叫做 S-Expression。這個 S,其實就是 Symbolic 的意思。 把程序和數據都統一的當成符號,用現代編程語言的話說,就是 LISP 支持meta-programming。LISP 程序可以處理,生成和修改 LISP 程序。這個特性,加上函數是一階對象的特性,使得 LISP遠遠比同時代的任何語言靈活。我本人不是 LISP 的用戶(初級用戶都算不上),因此在這一點上所知有限。但單就我有限的對 LISP 的理解,我認為LISP 的這種靈活,恰好滿足了基于符號處理的 AI 領域對語言的“強大的表達能力”(可以對任何復雜系統建模)和“高層的抽象能力”的需求。關于第一點,有一個著名的段子,說任何一門編程語言技巧和思想被提出的時候,總會有一個高人出來,說,這個玩意兒在 LISP里面早就有了,具體的例子包括剛才說的 metaprogramming, object oriented language。這里面蘊含的,就是LISP 的強大的表達能力,使得很多編程的范式,在 LISP 里面都能實現,或者找到影子。 關于第二點,SICP中例子比比皆是,講得都比我深刻許多,就無需廢話了。
在上篇文章中我提到,翻開任何一本編程的書,都會講到“LISP是適合 AI 的編程語言”。那么,如果您和我當年一樣,有興趣從事 AI方面的研究和探索,就不免要疑惑:“為了學習 AI, 我要不要學習 LISP”呢?現在距離我當年的這個疑惑已經差不多8年了,我并沒有一個確定的答案,但是我知道了更多的一些事實。
如今的AI 范式
如果你讓任何一個 AI 方向的研究者推薦幾本適合初學者的書的話,十有八九他會提到 “Artificial Intelligence: AModern Approach”(人工智能,一種現代方法) 和 “Artificial Intelligence: A NewSynthesis” (人工智能,一個新的綜述)。 這兩本書的作者分別是 Peter Norvig 和 Nils Nilsson,都是 AI領域的元老級人物。 如果你是一個對書名很敏感的人,你肯定會想:奇怪了,這種書又不是暢銷書,難道這兩位大牛寫了書怕賣不出去,非要在書名上加一個“現代” 或者 “新” 來吸引眼球? 事實上,這個“現代”和這個“新”都大有來頭。 實際上,這二十年來,AI 研究領域接連發生了好幾個非常大的paradigm shift. 傳統的基于符號的 AI方法不再是主流,取而代之的,是多種多樣的基于統計的,基于自動推理的,基于機器學習的,基于群體智慧的,基于大規模數據集的等等各種各樣研究方法的興起。 這個 paradigm shift, 對于領域之外的人好像是靜悄悄的,可實際上 AI 領域早已發生了翻天覆地的變化。所以才會有 “新” 和“現代” 這樣的詞出現在書標題上。 不幸的是,大多寫編程語言書的作者,未必全部知曉這個變化,因此還沿襲原來的框架,繼續寫下 “LISP是適合AI 的編程語言” 這樣一個早就不能完全反映現狀的斷言。 如果我們統計一個從事 AI研究的研究者或者科學家用什么語言,答案可能是五花八門無所不有: 做 AI Search 的用 C/C++/Java,做機器學習的如果模型和矩陣關系密切,可以用 Matlab, 如果統計計算較多,也可以用 R。至于做數據挖掘等等,語言和庫更加五花八門,根本無法宣稱那一個語言占上風。LISP 是適合 AI的語言的教科書神話,也早就被無數的這樣的實例給打破了。