2007年12月26日星期三

函數編程之風雲再起

作者:蔡學鏞

甫於11/30北京落幕的Software Development 2.0研討會,來賓之一的Andrei Alexandrescu被問到未來編程語言的趨勢時,他認為函數編程(Functional Pogramming)可能會再度興起。我認同他的看法,過去我在其他IT雜誌上發表JavaFX文章時,碰巧也有提到這一點。

目前主要是學術圈在使用函數語言(Functional Language),但確實有相當多跡象顯示,函數編程有可能會漸漸走入業界。

目前兩大開發平台上(Java與.NET),都出現函數編程思維的蹤跡。Java平台的JavaFX語言,具備所有重要的函數編程特色,所以應該歸類為函數語言(或者至少是多重思維語言);.NET平台的C# 3.0納入相當多函數編程的特色,微軟的LINQ本來就是源自函數語言,更不用提微軟官方的F# 語言更是徹底的函數語言(其中F應該是Functional的意思),沿用相當多ML語言的語法。

根據Tiobe對於2007年12月語言需求所做的統計,物件導向語言佔54.4%,程序語言(Procedure Language)佔有41.9%,函數語言佔有2.0%,而邏輯語言佔有1.8%。加起來剛好百分之百。

這樣的分類並不精確。現在的語言很少是單一思維的,幾乎都是多重範式(Multi-paradigm),特別是物件導向和函數編程並沒有衝突的地方,許多物件導向語言會漸漸納入函數編程的特色。例如,儘管C# 3.0具有相當多函數語言的特色,但是依然會被Tiobe歸類於物件導向語言。

函數編程的最重要基礎是Lambda Calculus,不同語言會用不同的方式稱呼它:C# 3.0稱為「Lambda表示式」,Python稱為「Lambda函數」,PowerShell稱為Scriptblock(劇本區塊),Java稱為匿名方法(anonymous method),但其實都是類似的東西。從這個角度來看,許多主流語言都多多少少具備函數編程的能力。而這個趨勢應該會延續下去,許多既有的語言推出新版本時會持續加入各種源自於函數語言的特色。

我最喜歡的REBOL,許多人工智慧專家使用的Common Lisp,近年異軍突起的Erlang,Perl高手唐鳳專精的Haskell,這些也都是函數語言。為什麼我們喜歡函數編程?因為我們可以真正把時間花在有生產力的事情上,而不是處理許多瑣碎的事。簡單地說,函數語言可以讓我們用簡單的方式寫程式,但是威力又強大。

編程語言專家Ravi Sethi教授認為簡單與威力,正是函數編程的兩大優勢。函數編程的簡單,來自於以值(value)為中心,不用理會下面平台是什麼機器、記憶體要如何配置、如何指定。威力來自於遞迴以及將函數視為「first-class」(一等)的值(也就是說,函數本身就是值,可以被傳遞、被指定。)

自動記憶體管理雖然是始於函數語言,但是近年已經進入各大主流語言。將函數視為一等的資料型別,也開始進入各大主流語言。這些都要歸功於函數語言,尤其是Lisp。

Lisp是函數語言的始祖,誕生於1958年,相當於50年前。換算成人類的年紀,已經是人瑞了。Lisp的後繼者眾,其中至今最活躍者是誕生於1980年代的Common Lisp,它在Tiobe的排名是17。在Peter Seibel寫出《Practical Common Lisp》一書,並得到Jolt Award之後,漸漸讓大家對Common Lisp一改印象,開始認為它不只是學術上的語言,而是一種務實的語言。

一般來說,相較於C、Pascal這類命令式編程(Imperative Programming),函數編程的缺點是效率比較差,這是函數語言一直沒有流行的主因之一。但是現在CPU速度提升,編譯器技術進步,都讓效率不再是問題。甚至在數學運算上,用Clean與OCaml(都是函數語言)開發出來的程式,效率並不會比C差。

尤其是在多核心CPU和分散式運算時代,函數編程更是比imperative編程具有更強的優勢。例如近年逐漸受到重視的Erlang,正是將重點放在Concurrency與容錯上。用Erlang可以輕鬆開發出來的系統,如果改用別的語言開發,可能會造成程式長度暴增,以及不穩定的狀況嚴重。

如果你想學習函數編程,且如果你使用.NET平台,建議你使用F#;如果你使用Java平台,你可以考慮JavaFX;如果你沒有Java與.NET平台的考量,你可以選擇Common Lisp與Erlang。

大多數的人沒有使用過函數編程技術,所以思維會受到傳統imperative編程作法的拉扯,一開始很不習慣。只要堅持下去,跨過門檻之後,你會發現,函數編程其實更自然,生產力更高

有些技術沒被大眾接受,不是因為它不好,是因為環境不能配合等因素。現在的網路、多核心、高速的CPU、軟體複雜度…等環境因素,正是適合函數編程生存的環境,值得我們持續關注它的發展。