关于Functors、Monads等FP概念的理解是否正确?(JS实践视角)
函数编程核心概念的正误梳理与补充
一、你的简化理解正误分析
1. Monoids
核心理解正确:Monoid是能将两个同类值组合成同类型值的抽象。但需补充两个关键约束:
- 必须满足结合律:比如
(a + b) + c = a + (b + c),字符串拼接、数组concat、纯函数组合都符合; - 存在单位元:即一个“中性值”,和任何值组合都不改变原结果,比如加法的
0、字符串的""、函数组合的恒等函数x => x。
JS里数组push不算Monoid(属于可变操作),但concat是;函数组合需确保是纯函数才符合Monoid要求。
2. Maps
定义基本准确:Map是对容器(集合或包装类型)的每个元素应用函数,返回同类型容器且长度不变的操作。比如数组的map、Promise的then(传入函数不返回Promise时)都属于这类操作。
3. Functors
此处有误:Functor不是“返回自身的对象”,而是返回同类型新实例的容器类型,且必须满足两条函子定律:
- 恒等定律:用恒等函数
x => x映射后,结果与原容器等价,比如[1,2].map(x=>x)和原数组等价; - 组合定律:先映射函数f再映射函数g,等价于映射f与g的组合函数,比如
[1,2].map(x=>x+1).map(x=>x*2)等于[1,2].map(x=>(x+1)*2)。
JS里的数组、Promise、Maybe、Either都是Functor。
4. Monads
表述基本正确:Monad是支持flatMap(或bind)操作的Functor。需明确flatMap是Monad核心操作,且Monad必须满足三条单子定律:
- 左单位元:用
unit(包装普通值的方法)把值x包装后,再flatMap函数f,结果等于直接调用f(x),比如Promise.resolve(x).then(f)等于f(x); - 右单位元:Monad实例flatMap
unit方法,结果等于原实例,比如Promise.resolve(x).then(Promise.resolve)等于原Promise; - 结合律:先flatMap f再flatMap g,等价于flatMap一个先调用f再调用g的组合函数,比如
p.then(f).then(g)等于p.then(x => f(x).then(g))。
5. FlatMaps
定义不够精准:FlatMap本质是先Map再Flatten(扁平化)。比如数组的flatMap:[1,2].flatMap(x=>[x,x*2])先得到[[1,2],[2,4]],再扁平化为[1,2,2,4];Promise的then当传入函数返回Promise时,自动展开嵌套的Promise(把Promise<Promise<T>>变成Promise<T>),这就是FlatMap的行为。核心作用是解决嵌套容器问题,避免多层嵌套带来的代码复杂度。
6. Either、Maybe、Bind、Then
存在概念混淆:
Bind是Monad操作的通用名称(比如Haskell里的>>=),JS中Promise的then在处理返回Promise的函数时,等价于Bind/FlatMap;Maybe和Either是具体的Monad类型,内部实现了FlatMap逻辑,但本身不是FlatMap;- 二者使用场景差异:
- Maybe:处理“值可能不存在”的场景,分为
Just(value)(有有效值)和Nothing(无值)。链式调用时只要遇到Nothing,后续操作全被跳过,避免null/undefined引发的Cannot read property...错误。比如获取嵌套对象属性:Maybe.of(user).map(u=>u.address).map(a=>a.street),若user或address为null,直接返回Nothing,不会报错。 - Either:处理“操作可能失败”的场景,分为
Right(value)(成功结果)和Left(error)(错误信息)。和Maybe不同,Left可携带具体错误原因(如错误码、消息),适合需要明确错误类型并针对性处理的场景。比如API请求失败时,用Left返回错误码,Right返回响应数据。
- Maybe:处理“值可能不存在”的场景,分为
二、补充遗漏的关键要点
- Unit/Of方法:所有Monad都必须有
unit(或of)方法,用于将普通值包装成Monad实例。比如Promise的Promise.resolve()、Maybe的Maybe.of()、Either的Either.right()都属于这类方法。 - 核心目的:隔离副作用:这些概念的核心价值之一是隔离副作用(异步操作、错误、空值等),让业务逻辑更纯粹、可预测。比如用Either替代try/catch,分离错误处理与业务逻辑;用Promise处理异步,避免回调地狱。
- 概念层级关系:Monoid与Functor/Monad是不同维度的抽象:Monoid关注“值的组合”,Functor关注“容器的映射”,Monad关注“嵌套容器的链式操作”。部分类型可同时属于多个抽象,比如数组既是Monoid(通过
concat),也是Functor(通过map),还是Monad(通过flatMap)。
内容的提问来源于stack exchange,提问作者Kleber Germano
相关产品推荐
相关产品推荐

