3-25.【函数式编程】Monad 与 Functor 的区别?

6 阅读1分钟

Monad 与 Functor 的区别?Optional / Result 是如何体现 Monad 的 bind (flatMap) 语义?

1️⃣ Functor vs Monad

特性FunctorMonad
核心操作mapflatMap(或 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平铺嵌套容器
  • 只处理 successfailure 自动传递
  • 链式组合多个可能失败操作非常自然
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️⃣ 核心总结

概念FunctorMonad
基本操作map(f: (A)->B)flatMap(f: (A)->M<B>)
是否处理嵌套❌ map(A->M) 会嵌套✅ flatMap 平铺嵌套
容器类型Optional, Result, Array 等Optional, Result, Array 等
适用场景单值映射链式调用、可能失败操作、容器嵌套解包
Swift 示例Optional.map, Result.mapOptional.flatMap, Result.flatMap

简单记忆:

  • Functor = “容器里的值做映射”
  • Monad = “容器里的值做映射,并平铺嵌套容器”