用途
functional 技能用于在编写逻辑、进行数据转换或遇到因变更(mutation)导致的缺陷时,提供一套实用的函数式编程模式。它的触发范围包括任何构建、合并、过滤、排序、计价或以其他方式重塑记录、列表、购物车、订单、发票的功能请求,即使请求文字中从未提到不可变性。对于这类改动,建议与 tdd 技能同时加载,而不是用本技能替代 tdd。此外,当在已经使用 Effect 的项目中组合 Effect 程序,或审查 Effect 运行时边界时,也应使用本技能。技能明确提醒:除非项目本身需要,不要过度套用 monad、fp-ts 等重型函数式抽象。
主要能力
技能提供按需加载的深度资源,位于 resources/ 目录:
immutability-catalog.md:在修复变更缺陷、应用readonly/ReadonlyArray类型,或查找数组/对象变更的不可变替代方案时加载。composition-patterns.md:在将小函数组合成管道、重构单体逻辑或扁平化深层嵌套代码时加载。effect-runtime.md:在基于 Effect 的项目中处理运行时边界、服务需求、失败处理、中断或资源生命周期时加载。
核心原则包括:默认使用不可变的领域数据,先构建结果再返回,任何变更只停留在创建该值的函数内部,绝不触及调用方仍持有的值;尽可能使用纯函数;优先组合而非继承;优先自文档化代码,保留解释约束或非显而易见原因的注释;在遍历每个元素、折叠为累加器或构建查找表时使用 map/filter/reduce 等数组方法,循环只在需要提前退出或执行副作用时才有立足之地;对参数分组使用 options 对象,让简单的位置参数 API 保持简单。
使用方式
技能以原则与示例的形式给出落地指导。声明数据类型时,应将每个属性标记为 readonly,每个数组标记为 ReadonlyArray<T> 或 readonly T[],包括添加到已有文件中的类型,以及参数位置的内联 { ... }[],让编译器强制约束契约;可变属性应是被论证的例外而非默认。技能给出不可变性为何重要的说明:让代码可预测(相同输入产生相同输出,无隐藏状态变化)、可调试、可测试,并且对 React 友好(协调与记忆化可依赖引用变化);它也能减少共享状态的并发风险,但本身不能阻止 I/O 或协调中的竞态。
在方法选择上,技能说明:用 map 做一对一改写、filter 保留子集、reduce 做累加、按字段建立查找或分组(包括调用辅助函数的折叠),按字段键控的查找建议使用 Object.groupBy 或 reduce 构建的 Map;当 Array.find()、Array.some()、Array.every() 更直接表达意图时应优先选用。已经使用 break 或 return 提前退出的循环应保留,而不是把提前退出硬塞进方法链。
在参数设计上,当参数构成有意义的分组、多个值类型相同、或可选参数使顺序不明确时,使用 options 对象;简单稳定的位置参数函数可以保持位置参数。在纯函数部分,技能定义纯函数为无副作用且相同输入始终返回相同输出,并给出三条标准:无副作用、确定性、引用透明;同时说明当必须引入不纯时,应将其隔离在边界(纯核心 + 不纯外壳),保持具体 I/O 位于项目选定的边界,核心领域决策保持纯净。
技能还介绍用提前返回(guard clauses)代替深层嵌套,当嵌套控制流遮蔽主路径时应提取函数或扁平化;并介绍 Result 类型,用于预期失败属于调用方面向契约、调用方必须处理两个分支的场景,同时提醒在既有异常、可空值或框架错误约定表达更清楚时保留该约定。
适用场景
适用于编写业务逻辑、数据转换与重塑,处理记录、列表、购物车、订单、发票等场景;修复变更类缺陷;在 React 等依赖引用变化的场景中维护可预测状态;在已使用 Effect 的项目中需要组合 Effect 程序或审查其运行时边界时。
限制
技能明确要求不要过度套用重型函数式抽象(monad、fp-ts),除非项目需要;目标是可维护、可测试的代码,而非学术纯粹性,如果某种函数式模式让代码更难理解就不应使用。小纯函数是实现技术,并不意味着每个模块发布一个函数;相关辅助函数在一个内聚职责下应保持私有并就近放置。异常、可空值或既有框架错误约定在某些情况下仍应保留。技能中未提供收费、价格、平台支持情况等事实信息。