Go 程式設計教學:函數式程式設計 (Functional Programming)

PUBLISHED ON NOV 9, 2017 — PROGRAMMING

函數式程式設計 (functional programming) 是另一種程式設計模範 (paradigm),其思想主要可見於 LISP 和 ML 家族的程式語言。雖然函數式語言不是主流,但函數式程式易於平行處理,近年來又逐漸抬頭。一些主流程式語言,包括 C++、Java、C# 等,都加入一些函數式程式的特性。大數據 (big data) 框架 Hadoop 和 Spark 的思想,也是基於函數式程式。Go 雖然不是函數式語言,但提供一些函數式程式的特性。

函式物件

函數式程式的基本前提是函式為一級物件,簡單地說,函式也是值,可以做為參數也可做為回傳值。例如,以下是合法的 Go 程式:

在本例中,我們建立一個函式物件 f,再呼叫之。

高階函式

我們也可以將函式物件做為另一個函式的參數,這種函式稱為高階函式 (higher-order function)。見下例:

在本例中,我們對同一個函式 apply 傳入不同的函式,得到不同的結果。

閉包

函式物件除了做為參數,也可以做為回傳值。見下例:

在本例中,每次呼叫函式 f,得到的數值會遞增 1,這種帶有狀態的函式,稱為閉包 (closure)。

Strict Evaluation vs. Lazy Evaluation

主流的程式語言大抵上都是 strict evaluation,例如,以下的 Go 程式是錯的:

但以下等效的 Haskell 程式是正確的:

這是由於 Haskell 有 lazy evaluation 的特性。

純函式

純函式 (pure function) 是函數式程式設計的一個概念,對於純函式來說,只要輸入的參數是相同的,得到的輸出就是相同的;換句話說,純函式沒有副作用 (side effect)。副作用在電腦程式中相當常見,像是改變某個物件內在狀態、將結果輸出到終端機、將資料存入外部檔案等;然而,過度依賴函式的副作用,有時候反而造成預期外的錯誤。函數式程式設計的其中一個概念就是減少副作用。Go 沒有特別強調純函式的觀念,但程式設計者可在撰寫程式時盡力避免副作用。

遞迴

遞迴不是函數式程式設計專有的特性,即使像是 C 這種非函數式程式語言也有遞迴的機制。然而,函數式程式語言支援 tail-call optimization,使得遞迴和控制結構達到相近的速度;Go 未支援此項特性。

型別推論

型別推論 (type inference) 也是函數式程式設計的其中一項特色,很多函數式程式語言都內建這項功能,像是 Haskell 或是 OCaml 等。Go 吸收這項特性,使得 Go 在某些方面類似動態型別語言。

comments powered by Disqus