函式是一等公民
Higher-Order Function(HOF)的前提是:語言裡的函式是一等公民(first-class citizen)——可以被賦值給變數、當參數傳、當返回值返回。JavaScript、Python、Go、Kotlin 都支援。
// 函式賦值給變數
const double = (x) => x * 2;
// 函式當參數(HOF)
function applyTwice(f, x) {
return f(f(x));
}
applyTwice(double, 3); // 12
// 函式當返回值(closure)
function multiplier(factor) {
return (x) => x * factor; // 返回一個函式
}
const triple = multiplier(3);
triple(5); // 15map / filter / reduce
陣列操作的三個基本 HOF,幾乎每個應用都在用:
orders = [
{"product": "Laptop", "price": 1200, "category": "Electronics"},
{"product": "Book", "price": 25, "category": "Education"},
{"product": "Phone", "price": 800, "category": "Electronics"},
]
# filter:篩選電子產品
electronics = filter(lambda o: o["category"] == "Electronics", orders)
# map:提取價格
prices = map(lambda o: o["price"], electronics)
# reduce:加總
from functools import reduce
total = reduce(lambda acc, price: acc + price, prices, 0)
# 用 method chaining 更清楚(List comprehension 版)
total = sum(
o["price"]
for o in orders
if o["category"] == "Electronics"
)Curry 和 Partial Application
Curry:把接受多個參數的函式,轉成一系列接受一個參數的函式。
// 普通函式
const add = (a, b) => a + b;
// Curried 版本
const curriedAdd = (a) => (b) => a + b;
const add5 = curriedAdd(5); // 固定第一個參數
add5(3); // 8
add5(10); // 15Partial Application:固定部分參數,返回一個需要剩餘參數的函式。
from functools import partial
def multiply(a, b):
return a * b
double = partial(multiply, 2) # 固定 a=2
double(5) # 10
double(10) # 20函式組合(Function Composition)
把多個小函式串起來,輸出到下一個輸入:
const compose = (...fns) => (x) => fns.reduceRight((acc, fn) => fn(acc), x);
const trim = (s) => s.trim();
const toLowerCase = (s) => s.toLowerCase();
const addPrefix = (s) => `user:${s}`;
const normalizeUsername = compose(addPrefix, toLowerCase, trim);
normalizeUsername(" ALICE "); // "user:alice"這是 Unix pipe 的函式版:trim | toLowerCase | addPrefix。
和 GoF Pattern 的連接
Strategy Pattern 在物件導向裡是「把算法封裝成物件」。在函數式裡,直接傳函式就達到同樣的效果——不需要建一個 SortStrategy interface 和 QuickSortStrategy class,直接 sort(array, (a, b) => a - b)。
HOF 讓很多 GoF Pattern 在函數式語言裡變成「直接傳函式」的慣用法,而不是複雜的類別階層。