You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在fp-ts中是否存在Do/Bind模式用于创建多类型对象?

解决方案:实现极简同步版Do/bind工具

你的核心需求是无额外包装的同步链式对象构建,不需要引入IO/Option/Either这些带额外语义的Monad,完全可以自己实现一套极简的Do和bind函数,完美匹配你想要的写法:

1. 实现核心工具函数

// 辅助类型:跟踪已绑定的键值对
type Bindings = Record<string, unknown>;

// 初始空容器,对应你想要的R.Do
const Do = {} as Bindings;

// 自定义bind函数:接收键名和依赖已有绑定生成值的函数
function bind<K extends string, V, B extends Bindings>(
  key: K,
  valueFn: (bindings: B) => V
) {
  return (currentBindings: B): B & Record<K, V> => {
    const value = valueFn(currentBindings);
    return { ...currentBindings, [key]: value };
  };
}

2. 重构你的getZ函数

用上面的工具函数,你可以完全按照最初的预期写法实现,没有任何冗余包装:

// 假设已有这些类型和函数定义
type A = /* 你的A类型 */;
type B = /* 你的B类型 */;
type C = /* 你的C类型 */;
type D = /* 你的D类型 */;

function getB(a: A): B { /* 实现逻辑 */ }
function getC(b: B): C { /* 实现逻辑 */ }
function getD(c: C): D { /* 实现逻辑 */ }

type Z = {
  a: A,
  b: B,
  c: C,
  d: D,
};

const getZ = (a: A): Z => pipe(
  Do,
  bind('a', () => a),
  bind('b', ({ a }) => getB(a)),
  bind('c', ({ b }) => getC(b)),
  bind('d', ({ c }) => getD(c)),
) as Z;

3. 方案优势

  • 无冗余代码:不需要任何IO.of()/O.some()这类包装,所有操作都是纯同步函数
  • 保留中间值:每个bind都能直接访问之前绑定的所有属性,满足后续转换需求
  • 类型安全:TypeScript能正确推导绑定过程中的类型,最后通过类型断言得到最终的Z类型(也可以优化类型定义让推导更自动)

备选方案:用fp-ts的Identity Monad

如果你不想自己实现工具,也可以用fp-ts中最轻量化的Identity Monad,它只是一个无任何额外语义的包装,运行时开销极小:

import * as I from 'fp-ts/Identity';

const getZ = (a: A): Z => pipe(
  I.Do,
  I.bind('a', () => I.of(a)),
  I.bind('b', ({ a }) => I.of(getB(a))),
  I.bind('c', ({ b }) => I.of(getC(b))),
  I.bind('d', ({ c }) => I.of(getD(c))),
  (identity) => identity.value,
);

内容的提问来源于stack exchange,提问作者Manav Chawla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:55:19