跳到主要内容

函子与单子

函子(Functor)和单子(Monad)是函数式编程中的抽象概念,它们为处理容器类型提供了统一的接口。

什么是函子?

函子是实现了 map 方法的容器类型,它允许你将一个函数应用到容器中的值。

// 函子接口
class Functor {
map(fn) {
// 将函数 fn 应用于容器中的值
}
}

函子定律

  1. 同一律functor.map(x => x) 等于 functor
  2. 组合律functor.map(x => f(g(x))) 等于 functor.map(g).map(f)

简单函子实现

class Container {
constructor(value) {
this.value = value;
}

static of(value) {
return new Container(value);
}

map(fn) {
return Container.of(fn(this.value));
}
}

// 使用
Container.of(5)
.map(x => x + 1)
.map(x => x * 2);
// Container { value: 12 }

什么是单子?

单子(Monad)是函子的扩展,它增加了 flatMap(或 chainbind)方法,用于处理嵌套容器。

// 单子接口
class Monad {
map(fn) { /* ... */ }
flatMap(fn) { /* ... */ }
}

单子定律

  1. 左同一律Monad.of(x).flatMap(f) 等于 f(x)
  2. 右同一律m.flatMap(Monad.of) 等于 m
  3. 结合律m.flatMap(f).flatMap(g) 等于 m.flatMap(x => f(x).flatMap(g))

Maybe 单子

class Maybe {
static just(value) {
return new Just(value);
}

static nothing() {
return new Nothing();
}

static of(value) {
return value == null ? new Nothing() : new Just(value);
}
}

class Just extends Maybe {
constructor(value) {
super();
this.value = value;
}

map(fn) {
return Maybe.just(fn(this.value));
}

flatMap(fn) {
return fn(this.value);
}

getOrElse(_) {
return this.value;
}
}

class Nothing extends Maybe {
map(_) {
return this;
}

flatMap(_) {
return this;
}

getOrElse(defaultValue) {
return defaultValue;
}
}

实际应用

处理可能为空的值

const user = {
profile: {
address: {
city: 'New York'
}
}
};

// 命令式风格
const city = user && user.profile && user.profile.address && user.profile.address.city;

// 使用 Maybe
const getCity = (user) =>
Maybe.of(user)
.flatMap(u => Maybe.of(u.profile))
.flatMap(p => Maybe.of(p.address))
.map(a => a.city)
.getOrElse('Unknown');

Promise 也是单子

// Promise 实现了单子接口
Promise.resolve(5)
.then(x => x + 1) // map
.then(x => Promise.resolve(x * 2)) // flatMap
.then(console.log); // 12

数组作为函子

// 数组是函子
[1, 2, 3].map(x => x * 2); // [2, 4, 6]

// 数组也是单子(通过 flatMap)
[1, 2, 3].flatMap(x => [x, x * 2]); // [1, 2, 2, 4, 3, 6]

总结

  • 函子:提供 map 方法,用于转换容器中的值
  • 单子:扩展函子,提供 flatMap 方法,用于展平嵌套容器
  • 优势:统一接口、链式操作、处理副作用