在軟體工程開發的領域中,我們為了解決不同的問題,因此衍生出許多不同的程式設計(Programming paradigm)方式,這些設計方法彼此之間並沒有所謂的好壞、優劣,只有解決問題適合度高低的差異。
函數式編程
(Functional Programming
,以下簡稱 FP)是眾多程式設計(Programming Paradigm) 方式的其中一種,有別於老早就大紅大紫的物件導向編成(object-oriented Programming,OOP) 方式(OO還衍伸出許多設計模式),FP 則是近年來較為熱門的程式設計方式。像是 React 這套 JavaScript 框架就是使用 FP 來開發程式,因此若想學習 React.js 勢必也要熟悉 FP 的基本概念,而 JavaScript 程式語言也需要符合 FP 的編程理念。本篇將以 JavaScript 作為出發,解釋 JavaScript 函數式編程的重要概念。
本篇皆以 JavaScript 為範例。
First-class & higher-order functions
First-class(一等公民)
我們可以想像成對待函式(Functions) 如同對待其他資料型別一樣。
例如:可以直接賦予值或者存至陣列中當作參數傳遞。
例如,我們可以宣告:
|
|
1 的值也就指定給 a。
因此我們也可以直接將函式(Functions) 指定給任一變數:
|
|
a 也就變成 (x * y) Function 的變數,呼叫 a(2, 4) 則會返回值 8。
higher-order functions(高階函式)
在維基百科中高階函式至少會滿足下列其中一項條件:
- 可以將函式(至少一個)當成參數傳入另一個函式。
- 可以將函式當成另一個函式的回傳值。
|
|
由上述範例我們可以得知,add 函式接收參數 (x),並且回傳一個函式 ( x + y ) 作為回傳值。
因此在宣告 addFive 變數時,同時給定 x = 5 至 add 函式,往後使用 addFive 變數(函式變數)皆會從 5 開始加減。
上述則是符合 higher-order functions 的例子,add 函式(Functions) 接收參數並且回傳一個函式(Functions) 作為回傳值。
函數柯里化文章可參考之前撰寫的(【Function Currying】Javascript 函數柯里化)[/2023-03-16/js-function-currying/]
Pure Functions
Pure Functions(純函式),意指將相同的 input 丟入函式,永遠會回傳相同的 output 結果,而且在過程中完全沒有任何的副作用。此處的副作用通常意味著「避免狀態改變」、「避免資料改變」,我們可以想成不與函式區塊域(block) 以外的變數做互動(最典型的例子,修改全域變數的值),或者不論函式以外做了什麼,函式(Functions) 內的運算依舊不受改變。換句話說,Pure Functions 擅於純運算,而不做其他事情(ex. 讀取外部資料)。
範例如下:
|
|
在 Functional Programming 中,slice 函式(Functions) 就符合我們 Pure Functions 的規範,相同 input,永遠回傳相同 output 且無副作用。而 splice 函式(Functions) 則是每次呼叫,output 以及原始資料皆會不相同,因此不算是 Pure Functions。
副作用
以 JavaScript 為例, 副作用還包括:
- 更改外部變數或者物件屬性(例如:全域變數、父類別範圍內的變數等)
- 寫入 console.log、檔案
- 觸發外部流程
- 呼叫任何有副作用的函式(Functions)
Declarative vs Imperative
函數式編程(Functional Programming) 屬於宣告式編程(Declarative Paradigm) 的一種。
宣告式編程(Declarative Paradigm): 較為抽象的程式碼,可以藉由自然語言直觀的理解該行程式碼想要達到什麼樣的結果。描述該在哪做什麼(what to do)以及資料流程(data flow)。
指令式編程(Imperative Paradigm): 程式碼具體表達需要做什麼來達到目標。描述該做什麼(how to do)以及流程控制(flow control)。
|
|
宣告式編程(Declarative Paradigm) 較依賴表達式(expression),表達式是一個單純的運算過程,並且總是會返回值。屬於宣告式編程的程式語言有:HTML、SQL、LINQ。
指令式編程(Imperative Paradigm) 的程式碼經常使用程式語言基本的語句(statement),例如:for、while、if、switch…等等。屬於指令式編程的程式語言有:C、JAVA。
總結
函數式編程(Functional Programming) 誕生了五十多年後,終於獲得程式開發者大量的關注,目前 ML 非常紅的 Python 以及前後端 JavaScript 等語言,對於函數式編程(Functional Programming) 的支持都很強。本篇文章整理 JavaScript 符合函數式編程(Functional Programming) 概念的幾個元素(First-class、higher-order functions、Pure Functions),希望透過 JavaScript 的實例理解函數式編程所講述的核心理念為何。最後比較宣告式編程(Declarative Paradigm)以及指令式編程(Imperative Paradigm),對自己過去在軟體開發這塊領域所學的做個整理,理清並梳理已有的知識。