Monad 与 Functor 的区别?Optional / Result 是如何体现 Monad 的 bind (flatMap) 语义?
1️⃣ Functor vs Monad
| 特性 | Functor | Monad |
|---|---|---|
| 核心操作 | map | flatMap(或 bind >>=) |
| 输入输出 | (A -> B) 映射到 F<A> -> F<B> | (A -> M<B>) 映射到 M<A> -> M<B> |
| 容器内函数 | 函数返回普通值 | 函数返回同类型容器 |
| 组合能力 | 只能处理单层映射 | 可以处理“嵌套容器”,避免多层嵌套 |
| 规律 | 恒等 + 组合 | 左单位元 + 右单位元 + 结合律 |
简单理解:
- Functor 只能把函数应用到容器里的值
- Monad 可以把返回值本身是容器的函数“平铺”到容器中,避免嵌套
2️⃣ Optional 的 Monad 行为
普通 map (Functor)
let x: Int? = 5
let y = x.map { $0 * 2 } // Optional(10)
- 输入
(Int -> Int) - 输出
Optional<Int> - 不能直接处理返回 Optional 的函数,否则会得到
Optional<Optional<Int>>
func half(_ x: Int) -> Int? {
x % 2 == 0 ? Optional(x/2) : nil
}
let result = x.map(half) // Optional<Optional<Int>>
print(result) // Optional(Optional(2))
flatMap (Monad)
let result = x.flatMap(half) // Optional(2)
- 输入
(Int -> Optional<Int>) - 输出
Optional<Int>,平铺嵌套容器 - 避免 Optional
- 体现 Monad 的 bind 语义
完整示例
let numbers: [Int?] = [2, 3, 4]
func half(_ x: Int) -> Int? {
x % 2 == 0 ? x / 2 : nil
}
// 链式调用
let result = numbers.compactMap { $0 }.map(half) // [Optional(1), Optional(nil), Optional(2)]
let flatResult = numbers.compactMap { $0 }.compactMap(half) // [1, 2]
flatMap/compactMap可以“解嵌套”,体现 Monad 语义
3️⃣ Result 的 Monad 行为
普通 map (Functor)
let success: Result<Int, Error> = .success(10)
func toString(_ x: Int) -> Result<String, Error> {
.success("Value: (x)")
}
let mapped = success.map(toString)
print(mapped) // Result<Result<String, Error>, Error> ← 嵌套容器
map会把返回的 Result 包裹一层 → Result<Result<…>>
flatMap (Monad)
let flatMapped = success.flatMap(toString)
print(flatMapped) // Result<String, Error>
flatMap会平铺嵌套容器- 只处理
success,failure自动传递 - 链式组合多个可能失败操作非常自然
func addTen(_ x: Int) -> Result<Int, Error> {
.success(x + 10)
}
let finalResult = success
.flatMap(addTen)
.flatMap(toString)
print(finalResult) // Result<String, Error> -> "Value: 20"
4️⃣ 核心总结
| 概念 | Functor | Monad |
|---|---|---|
| 基本操作 | map(f: (A)->B) | flatMap(f: (A)->M<B>) |
| 是否处理嵌套 | ❌ map(A->M) 会嵌套 | ✅ flatMap 平铺嵌套 |
| 容器类型 | Optional, Result, Array 等 | Optional, Result, Array 等 |
| 适用场景 | 单值映射 | 链式调用、可能失败操作、容器嵌套解包 |
| Swift 示例 | Optional.map, Result.map | Optional.flatMap, Result.flatMap |
简单记忆:
- Functor = “容器里的值做映射”
- Monad = “容器里的值做映射,并平铺嵌套容器”