關於函數編程(一)On Functional Programming

函數編程 (functional programming) 1近幾年似乎漸漸跨出學術界,業界與黑客圈內對它的興趣也多了起來。每年參加 ICFP 的人越來越多,有不少是想來學習實用技術甚至發表結果的工程師。Epic Games 創始者,以 Unreal Engine 知名的 Tim SweeneyPOPL 06 應邀演講,以「下一個主流語言:一個遊戲設計者的觀點」為題,認為下一代的程式語言得要有效處理並行處理、模組化、與正確性的問題。解決之道呢?他認為函數語言應該要是預設的計算模型,並以強大的依值型別(dependent type)系統確保正確性。

這股風潮也吹到了中文世界。函數編程的中文資料已經不像以前那麼缺乏,簡體中文的翻譯與討論都不少。繁體中文圈倒是還得多加把勁。

對我來說,一方面高興有更多人對自己喜歡的東西有興趣,一方面卻得調適一下 — 好比喜愛的偏僻小鎮突然成了熱門觀光景點的那種不適應感。大家很熱情地談函數編程的好,這許多好處聽來倒讓我發現對這東西陌生了,一下子不知該怎麼回應才好。

開這個部落格時,我原本的打算大約也是如同英文首頁一樣,當作研究筆記用:做到哪就寫到哪,筆記著免得以後忘記了。所以才叫做小眾的計算科學嘛。經 Josh 提醒才認真想,我該不該寫個正式的函數編程介紹呢?

如果寫了,讀者是誰?以及是否還有這個必要?有歷史意義的文件中,John Hughes 流傳很廣的 Why Functional Programming Matters 仍歷久彌新,也有簡體中文譯本(但現在似乎不是很容易找到)。近來蔡學鏞也在他的部落格寫了一系列介紹函數編程的文章。我們還需要再多一篇嗎?

也許回到小鎮的比喻,就當作我在帶大家逛一些覺得不錯的小巷子吧。

純粹函數

如果物件導向是以物件為基本組成元素的程式設計觀念,函數程式設計 — functional programming 便是提倡以函數為基本單元來組織程式。這裡說的函數是純粹的數學函數:把一個輸入對應到一個輸出。如果我們用 fact 表示階層函數,fact 4 的值就是 1 × 2 × 3 × 4 = 24,而且一直都如此(對比之下,C 的所謂 function 即使每次呼叫給同樣的參數,仍可能傳回不同的值)。

我們以往教程式設計時喜歡用盒子的比喻:一個變數是一個盒子,賦值(assignment)指令改變變數裡存放的東西,例如 x := x + 1 把變數 x 裡的值加一後再放回 x 。然而數學上我們從更基礎的概念出發,只談存在與否而先不談變化;x 如果存在而且是某個值,那它以後就一直是這個值了。表現在語言上,純粹的函數語言沒有賦值的動作。一個函數除了把輸入對應到輸出之外,其他不務正業的事情,如賦值、檔案讀寫、在螢幕上畫圖等等都被稱作「副作用」。純粹函數語言是不可以有副作用的。

事實上,若精確地說,純粹函數語言在使用副作用前得有一個明確地描述它們的方法。這我們以後再談。

負向列舉?

無論如何,由指令語言的觀點看函數語言,注意到的第一件事情是「函數語言裡面不可以改變數的值」。於是大家難免覺得奇怪,這怎麼會是個優點呢?自廢武功去掉一個功能,會有什麼好處呢?

Hughes 把這種情形和結構化程式設計做了比較。在結構化程式設計被人們了解之前,人們對它的印象是「不准用 GOTO 的程式設計。」這是一個負向的定義,談它「不是」什麼,但比較難看出它「是」什麼。此後關於結構化的討論一度變成了反方不斷找出「用 GOTO 會比較好」的程式,正方去解的寫程式比賽,直到大家漸漸了解結構化的目的是為了促進模組化。而結構化程式設計也不一定非用新設計的結構化語言不可。

函數編程亦然。我們需要一個好的談法來了解函數編程是什麼。

附註

  1. 「編程」這詞似乎仍以大陸使用較多。台灣較常用的稱呼是「程式設計」。但若把 “functional programming” 翻成「函數(式)程式設計」似乎又太冗長。台灣的大學若開 functional programming 課程,習慣的課名是「函數語言」,但寫作上如果要談的是 functional programming 這個典範,要把句型改成指涉函數「語言」總是很不便。本站目前把 functional programming 譯成「函數編程」,其他時候仍說「程式設計」。以後再視我能不能習慣「編程」這詞而定…

1 thought on “關於函數編程(一)On Functional Programming”

  1. Pingback: Go To 有害大論戰

Leave a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *