Simon Peyton Jones#
Simon Peyton Jones 是 Haskell 程式語言的核心推動者之一。1987 年,他參與發起了定義 Haskell 的計畫,編輯了 Haskell 98 Revised Report(語言的穩定定義),並且是 Glasgow Haskell Compiler (GHC) 的架構師與首席開發者。他在英國劍橋的 Microsoft Research 擔任首席研究員。2004 年,ACM 選舉他為 Fellow,表彰他「對函數式程式語言的貢獻」。他給了 Haskell 一個廣為人知的非官方座右銘:“Avoid success at all costs.”
Peyton Jones 從未取得博士學位,卻在學術界取得了傑出的成就。他認為 Robin Milner 也沒有博士學位,「這一定是很好的同伴」。
程式設計啟蒙#
學校時期:原始的機器碼#
- 大約 1973-74 年(15 歲左右),學校有一台 IBM 學校電腦,由大型主機的零件拼湊而成
- 這台機器沒有任何永久儲存,只有 100 個記憶體位置,每個可儲存 8 位十進位數字
- 程式和資料共用這 100 個位置,程式設計的核心挑戰就是把程式塞進去
- 輸入是觸控按鍵(約 20 個按鈕),輸出是電視螢幕
- 沒有 ASCII 字元,直接以十進位顯示機器碼——連組合語言都算不上
- 第一個有趣的程式:用 Newton-Raphson 近似法計算 24 位數平方根,塞進 99 個記憶體位置
技術學院的 Elliot 803#
- 搭乘很慢的公車到 Swindon 技術學院,使用一台巨大的 Elliot 803 大型主機
- 使用紙帶和電傳打字機,用 Algol 編寫程式——這是他的第一個高階語言
- 編輯程式的方式極其繁瑣:在紙帶上修改,本質上是「用物理介質的行編輯器」
劍橋大學時期#
- 進入劍橋大學讀數學,加入了大學電腦社團
- 使用大型主機 Phoenix,主要用 BCPL 程式設計
- 與朋友 Thomas Clarke 一起用 7400 系列 TTL 晶片自己動手造電腦
- 學校完全沒有電腦教學,全部是自學和嗜好式探索
- 每天晚上 9 點到凌晨 3 點在電腦室寫程式
Peyton Jones 認為沒有正式電腦科學訓練是把雙刃劍。他坦承自己對物件導向程式設計缺乏深層的「內臟感覺」(visceral feel),因為從未花數年時間撰寫大型 C++ 程式。
未完成的編譯器#
- 在劍橋期間,嘗試用 BCPL 為自己發明的語言撰寫編譯器
- 這個專案極其龐大且野心過大,最終從未完成
- 這是他首次體會到程式規模問題:程式大到無法全部裝在腦中
- 也是他第一次認真嘗試撰寫長期文件
職業生涯#
工業界短暫停留#
- 劍橋畢業後在一家小型過程控制與監控公司工作(約 12-15 人)
- 用 PL/Z 語言在 Z80 機器上撰寫即時作業系統
- 兩年後決定創業生活不適合自己——「創業者需要從金錢壓力中獲取能量,而我的能量會被這種壓力消耗」
學術生涯的開始#
- 在 University College London (UCL) 獲得講師職位(1982-83 年)
- 當時沒有博士學位,也沒有研究訓練
- 資深學者 John Washbrook 給了關鍵建議:「不管多麼卑微,開始做點什麼就好」
“Just start something, no matter how humble.” Peyton Jones 將這個建議傳授給每一位研究生。他說:「一旦開始轉動磨坊,電腦科學幾乎一切都會變得有趣,因為主題會像碎形一樣在你面前擴展。」
從未取得博士#
- 在 UCL 七年後考慮取得博士,但被任命為 Glasgow 大學的正教授
- 既然頭銜已經是「教授」,就放棄了取得博士的念頭
- 認為博士對研究生涯是必要但不充分的,但如果只是因為熱情而想深入,讀博士是極好的機會
函數式程式設計的理念#
接觸函數式程式設計#
- 在劍橋最後一年,修了 Arthur Norman 的短期課程
- Norman 展示了如何在純函數式語言中不使用副作用建構雙向連結串列——這讓 Peyton Jones 大開眼界
- David Turner 的 S-K combinators 論文也是關鍵啟發:展示了如何將 lambda calculus 翻譯成三個組合子(S、K、I),並能實際在硬體上實現
對函數式程式設計的定位#
- 他將純函數式程式設計定位為「對整個程式撰寫事業的一次激進而優雅的進攻」(a radical and elegant attack on the whole enterprise of writing programs)
- 不只是在牆上多加一塊磚,而是建造一面全新的牆
- 函數式程式設計最初很學術、很數學,但 20 年來一直在朝實用化邁進
Peyton Jones 用了一個精彩的比喻:「當命令式程式設計的石灰岩被磨掉時,函數式程式設計的花崗岩就會顯現出來。」(When the limestone of imperative programming is worn away, the granite of functional programming will be observed.)
學術研究的價值#
- 學術研究的好處是教授可以去做「看似瘋狂」的事情,不必立即證明其對底線的貢獻
- 如果不這樣做,就會陷入局部最優——「不斷漸進式地最佳化主流,卻困在一座矮山上」
- 函數式語言的許多概念已經滲透到主流:generics、generators、lazy streams、Python 的 list comprehensions
Lazy Evaluation(惰性求值)#
為什麼惰性求值很重要#
- Lazy evaluation 是一個巨大的激勵因素:函數不評估它們的引數,看起來像是一種全新的思考方式
- John Hughes 寫了一個只有四五行的程式,可以計算 e 的任意精度小數展開——「只要持續拉取串列的元素就好」
- John Hughes 的論文 “Why Functional Programming Matters” 是最早清楚闡述惰性求值重要性的文獻
惰性求值的模組化優勢#
- 惰性求值讓你能將生成器與消費者分離
- 例如:在西洋棋程式中,生成所有可能走法的生成器與進行 alpha-beta minimaxing 的消費者可以獨立開發
- 這種分離帶來更好的模組化 (modularity)
- 在 Haskell 中,程式設計師傾向寫下可能需要的輔助定義,不需要的不會被求值——這是一種程式設計便利性
惰性求值與 I/O 問題#
- 惰性求值使得 I/O 成為重大挑戰:在惰性語言中,副作用無法預測何時會發生
- 早期 Haskell 程式基本上只能是「字串到字串」的函數
- 這個困境最終促使他們發展出 Monads,這是惰性求值「逼我們走進角落」的意外收穫
Peyton Jones 認為關於惰性求值,最重要的一件事是它保持了語言的純粹性。「這不是它開始的方式——惰性求值很酷、是個好的程式設計習慣。但它開始的地方,最終引領我們走向 monads。」
型別系統與靜態型別#
型別系統的演進#
- 從 80 年代初期的簡單型別系統,到現在思考的是純函數式、命令式、並行程式設計透過 monads 的混合
- GHC 的中間語言是自身具有型別的 (typed intermediate language)——這是一大特色
- 中間語言的型別系統比原始語言更加通用和明確:每個函數引數都標註型別,只有型別檢查而非型別推斷
靜態型別 vs 動態型別#
- 承認自己有偏見,但認為大量程式可以良好地靜態型別化
- 型別系統在維護時特別有用:要對三年前寫的程式碼做系統性修改時,型別系統能確保一致性
- 型別簽名就像是函數式語言版本的 UML 圖——「它們是一種非常緊湊的規格語言」
- 認為靜態型別化「在適用的地方,每次都該使用,因為它有極好的維護效益」
- 但也承認型別系統的邊界還在擴展中,故事尚未結束
型別作為設計工具:Peyton Jones 設計程式時,很多時間花在思考資料型別上。「光是把資料型別弄對,你就已經說了很多關於程式做什麼的事。」型別簽名和程式碼的撰寫是交替進行的迭代過程,而非兩階段。
軟體設計方法#
設計的核心:找到正確的想法#
- 寫程式時,主要問題通常不是如何把想法轉成程式碼,而是找到正確的想法
- 以 GHC 後端重構為例:花了幾天思考如何把一個複雜步驟拆成兩個更簡潔的步驟
- 大量時間花在釐清資料型別上——「這不是真的在程式設計,而是在搞清楚想法」
泛化的平衡#
- 預設不寫很通用的東西,而是盡量寫出漂亮而清晰的程式碼
- 只有當發現自己多次寫本質上相同的程式碼時,才進行抽象和參數化
- 相比追求 general,更追求 beautiful
工具環境#
- 使用非常原始的工具:Emacs + GHC,僅此而已
- GHC 有 profiling 工具和大量中間輸出的 dump 功能
- 互動式 REPL (GHCi) 存在,但他個人傾向編輯和編譯的工作流
除錯方法#
編譯器除錯的特殊性#
- 除錯通常是看程式在編譯管線各階段的輸出:「這個階段看起來正常,這個階段出問題了,到底怎麼回事?」
- GHC 有 flag 可以批次 dump 各種中間結果
- 有時會散佈幾個 unsafe
printf來觀察實際執行狀態
對 print 除錯的坦承#
- 坦承主要使用「不安全的
printf」來除錯,對此並不自豪 - 但長期以來函數式程式除錯環境不足,這是最短路徑
- 函數式程式的 single-stepping 本身就是個有趣的研究問題——「怎麼對一個函數式程式做單步執行並不明顯」
對除錯器的看法#
- 不應該貶低好的除錯環境的重要性
- 在 .NET 等平台上,投入了數百人年開發的除錯器提供了「質的不同」的體驗
- 函數式語言採用的障礙之一就是缺乏好的 IDE 支援
測試與正確性#
QuickCheck#
- QuickCheck 是一個 Haskell 函式庫,根據函數的型別自動生成隨機測試
- Peyton Jones 認為寫下部分規格(properties)然後用動態或靜態方式檢查,比試圖寫完整規格更實用
- 「你永遠無法證明程式是對的,你只是在增加信心。我認為這就是任何人所能做到的。」
對形式驗證的看法#
- 完整的機器檢查正確性證明會遇到問題:規格本身變得跟程式一樣複雜
- 更實際的方法是寫下部分規格(partial specifications):「這棵樹應該永遠平衡」、「這個函數的回傳值應該大於零」
- 這些部分規格可以用 QuickCheck 的格式寫成 Haskell 函數來測試
即使號稱完整的規格也會遺漏資源限制、時間限制等。Peyton Jones 認為我們應該坦承「我們是在提高信心,而非證明完全正確」。
並行程式設計與 STM#
Software Transactional Memory (STM)#
- STM 不會獨自拯救世界——並行程式設計是多面向的野獸,需要多種範式
- 但 STM 完全優於 locks 和 condition variables:「忘了 locks 和 condition variables 吧」
- STM 的核心優勢是可組合性 (composability) 和簡單的推理原則
STM 的推理優勢#
- 使用 locks 時,很難在不了解所有鎖定策略的情況下推理程式正確性
- STM 提供了交易隔離 (transaction isolation):可以用純粹的循序推理來分析每個交易
- 即使交易中拋出例外,也不會破壞不變量——交易直接被放棄
STM 與 Haskell 的協同效應#
- Tim Harris 的 Java STM 演講啟發了 Peyton Jones 將 STM 引入 Haskell
- 在 Haskell 中,因為 loads 和 stores 是 monadic 的、非常明確,STM 的實現特別自然
- 發明了
retry和orElse操作——這些是在 Java 的複雜框架中從未被想到的 - STM 是函數式程式設計作為「實驗室」角色的完美範例:想法可以在純粹的環境中被更清楚地檢視,然後回饋到主流
雙向鏈結佇列的範例(來自 Maurice Herlihy):循序實現是大一程式設計題目;加上每個節點一個鎖的並行版本是研究論文等級的難題;但用 STM,只需在 insert 和 delete 操作外包裹
atomic就完成了。
推薦書籍#
Peyton Jones 的荒島書單:
- Jon Bentley — Programming Pearls
- Don Knuth — The Art of Computer Programming 系列
- Chris Okasaki — Purely Functional Data Structures(「每個人都應該讀,短而易讀」)
- Abelson & Sussman — Structure and Interpretation of Computer Programs
- Andrew Appel — Compiling with Continuations
- Dijkstra — A Discipline of Programming(介紹了程式推理的嚴謹方式)
- Per Brinch Hansen — 並行作業系統相關著作
對程式設計的哲學#
程式設計是什麼?#
- 讀了 Fred Brooks 的論文 “The Computer Scientist as Toolsmith”,很認同我們是在建造事物
- 但同時也熱衷於從具體的程式 artifact 中抽取可重用的原則
- 「學術研究的本質是從現實的混亂中抽象出可重用的思想」
工程 vs 工藝#
- 認為這是個假二分法——軟體工程既是工程也是工藝
- 專業軟體工程師難以真正感受所處理程式碼的巨大規模——「你透過一英尺見方的窗戶看帝國大廈」
- 函數式程式設計能建構更加健壯的結構,更容易理解、測試和推理
- 但「我們總是會拉伸我們的野心」——材料越堅固,我們就會建造越大的東西,直到再次超過極限
持續寫程式#
- 每天都寫一些程式碼,視之為自己的座右銘
- 「程式設計這麼有趣,你為什麼會不想做呢?而且它讓你保持誠實。」
- GHC 約有 80,000 行 Haskell 程式碼,已發展超過 15 年,仍在積極開發中
- 經常花時間重構和移動介面,或者整個重寫一大塊程式碼
Peyton Jones 常常會因為找不到漂亮的解法而推遲數週不動手,等到靈感來了才開始。「因為一定有個漂亮的方式來做這件事。」他在後台思考,偶爾嘗試,有時靈光乍現,有時只是「好吧,時間到了,就做吧」。
關於研究與實務的橋樑#
研究與產業的鴻溝#
- 開發者並非愚蠢地不採用好點子——他們有充分的理由做當前的事
- 研究想法需要額外的工程努力才能在現實中可用
- Microsoft Research 在橋接這個鴻溝方面做得相當好——有 incubation groups 幫助研究者和開發者互動
觀察程式設計師#
- 程式語言社群的文化傾向「證明你的型別系統是健全且完整的」
- 但更重要(也更難回答)的問題是:「它是否真的讓程式設計師更有生產力?」
- Steven Clarke 和同事在 Redmond 做了有趣的 API 可用性測試——讓程式設計師使用新 API,然後讓 API 設計者在單面鏡後面觀看
- 程式語言研究在這方面相對薄弱,但這些問題極為重要