函數式編程範式簡介
歡迎來到其中一種最有趣的編程思考方式!到目前為止,你可能已經習慣了程序式編程(procedural programming)(即給電腦一系列逐步執行的指令)或物件導向編程(object-oriented programming)(即創建相互互動的物件)。 在本章中,我們將探討函數式編程範式(functional programming paradigm)。我們不再逐步告訴電腦「如何」做某事,而是透過使用數學函數,專注於「想要達成什麼」。如果起初覺得這有點不同,不用擔心——把它想像成學習一種解決難題的新方法吧!1. 什麼是函數式編程?
你過去編寫的大部分程式都是指令式(imperative)的。這意味著你會改變程式的「狀態」(例如修改變數的值)。 函數式編程則是宣告式(declarative)的。在這種風格中,我們將計算過程視為數學函數的求值(evaluation),並避免改變資料。主要區別:
- 無副作用(No Side Effects):函數應該只回傳一個值。它不應改變自身外部的變數(例如全域變數)。
- 不變性(Immutability):一旦設定了數值,它就不會改變。與其修改一個列表,不如創建一個帶有更改的「新」列表。
- 無狀態(Stateless):程式不像迴圈計數器那樣追蹤「當前狀態」。
快速複習:指令式 = 「如何」做。宣告式/函數式 = 「做什麼」。
2. 作為一等公民的函數(Functions as First-Class Objects)
在函數式編程中,函數是一等公民(first-class objects)。這聽起來很高級,但其實意思很簡單:函數被視為與變數完全一樣!你可以對「一等公民」函數做什麼?
- 將函數指派給變數。
- 將函數作為參數傳遞給另一個函數。
- 從另一個函數中回傳一個函數作為結果。
3. 函數應用與組合
為了理解函數如何協同工作,我們使用兩個主要概念:應用(Application)與組合(Composition)。函數應用(Function Application)
這只是將參數提供給函數的過程。 例子:如果我們有一個函數 \( f(x) = x + 1 \),那麼將它應用於數字 \( 5 \),就會得到 \( 6 \)。我們寫作 \( f(5) \)。函數組合(Function Composition)
這是我們結合兩個函數以產生新函數的方法。一個函數的輸出會成為下一個函數的輸入。 如果我們有: \( f(x) = x + 1 \) \( g(x) = x \times 2 \) 組合 \( f(g(x)) \) 意味著我們首先將數字加倍,然後加 1。 如果 \( x = 3 \): 1. \( g(3) = 6 \) 2. \( f(6) = 7 \)記憶小撇步:將組合想像成接力賽。第一位選手(函數 G)將接力棒(結果)交給第二位選手(函數 F)來完成任務。
4. 定義域、陪域與映射
在函數式範式中,我們使用數學語言來描述資料如何流動。- 定義域(Domain):所有可能輸入值的集合。
- 陪域(Codomain):所有可能輸出值的集合。
- 映射(Mapping):將定義域中的輸入連結到陪域中輸出的規則。
關鍵重點:函數 \( f: A \to B \) 意味著函數 \( f \) 將集合 \( A \)(定義域)中的值映射到集合 \( B \)(陪域)。
5. 高階函數(Higher-Order Functions)
高階函數是指將另一個函數作為參數、回傳一個函數,或兩者皆是的函數。這是函數式編程變得非常強大的地方!你需要掌握三個主要的函數:A. Map(映射)
Map 接收一個函數和一個列表。它將該函數應用於列表中的每一個項目,並回傳一個新列表。 例子:對列表 \([1, 2, 3]\) 使用「翻倍」功能,結果為 \([2, 4, 6]\)。B. Filter(篩選)
Filter 接收一個條件(一個回傳 True/False 的函數)和一個列表。它回傳一個僅包含符合條件項目的新列表。 例子:對 \([1, 2, 3, 4]\) 使用「是否為偶數?」功能,結果為 \([2, 4]\)。C. Reduce(或 Fold,歸約)
Reduce 接收一個列表,並透過重複應用一個函數,將其「濃縮」為單一值。 例子:對 \([1, 2, 3, 4]\) 使用「相加」功能,結果為 \( 10 \) (\(1+2+3+4\))。你知道嗎?像 Google 這樣的大型科技公司使用「MapReduce」來同時處理成千上萬台電腦上的海量數據!
6. 列表:頭(Head)與尾(Tail)
函數式語言處理列表的方式通常與你習慣的陣列不同。它們將列表拆分為兩部分:- Head(頭):列表的第一個元素。
- Tail(尾):一個列表,包含除頭部之外的所有其餘元素。
總結檢查清單
你能解釋……- 指令式與宣告式編程的區別嗎?
- 函數作為一等公民是什麼意思?
- 組合是如何結合兩個函數的?
- 定義域與陪域的定義嗎?
- Map、Filter 和 Reduce 是如何運作的?
- 列表的 Head 與 Tail 有什麼區別?
如果起初覺得這些很棘手,別擔心!函數式編程是一種思維上的轉換。繼續練習「頭/尾」邏輯和高階函數,很快你就會豁然開朗!