前言
基于先前 Functor 与 Applicative Functor 的概念出发:
- Functor 通过
.map转换容器内的值,结果还是在容器内。
[2].map(x => x + 3) // [5]- Applicative 允许把“包起来的函数「套到」包起来的值”上,运算还是在包装中发生。
Maybe.of(x => x + 3).ap(Maybe.of(2)) // Maybe(5)但如果包装内返回内容被包装该怎么办呢?
Maybe.of(2).map(x => Maybe.of(x + 3))// 结果是 Maybe(Maybe(5))什么是 Monad?
function Maybe(value) { return value == null ? Nothing() : Just(value);}
function Just(value) { return { map: (fn) => Maybe(fn(value)), flatMap: (fn) => fn(value), getOrElse: () => value, };}
function Nothing() { return { map: () => Nothing(), flatMap: () => Nothing(), getOrElse: (defaultValue) => defaultValue, };}通过 flatMap(或叫 chain)会在运算后自动把包装摊平,让运算可以顺利的接续下去:
getUser(id) .flatMap(user => getProfile(user)) .flatMap(profile => getPosts(profile))举例数组:
const arr = [1, 2, 1];const result = arr.flatMap((num) => (num === 2 ? [2, 2] : 1));
console.log(result);// Expected output: Array [1, 2, 2, 1]Monad 定义
-
Left Identity
// 将值放入容器后,立刻 flatMap 一个函数// 等同于直接把该值传进该函数Monad.of(a).flatMap(f) ≡ f(a)// 示例const f = x => Maybe.of(x + 1)Maybe.of(2).flatMap(f) // => Maybe(3)f(2) // => Maybe(3) -
Right Identity
// 对一个 Monad flatMap of// 等同于什么都不做,这表示 flatMap 不会破坏原本的结构。m.flatMap(Monad.of) ≡ m// 示例Maybe.of(2).flatMap(Maybe.of) // => Maybe(2)Maybe.of(2) // => Maybe(2) -
Associativity
// 连续 flatMap 两个函数// 等同于 flatMap 一个合成函数// 这保证了多层链接时,不论括号怎么放,结果都一致。m.flatMap(f).flatMap(g)≡m.flatMap(x => f(x).flatMap(g))// 示例const f = x => Maybe.of(x + 1)const g = x => Maybe.of(x * 2)Maybe.of(2).flatMap(f).flatMap(g) // => Maybe(6)Maybe.of(2).flatMap(x => f(x).flatMap(g)) // => Maybe(6)
总结
Monad ⊇ Applicative ⊇ Functor
- Monad 是 Applicative 也是 Functor 的一种
- Applicative 是 Functor 的一种
开发上因为 flatMap 比 ap 更强大(它能做所有 Applicative 能做的事并有更多功能),所以不一定要实现 ap。