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

函数式编程中Algebraic Effects的含义及JavaScript示例问询

什么是函数式编程中的 Algebraic Effects?

简单来说,Algebraic Effects 是一种**分离"操作意图"和"操作实现"**的副作用处理机制,它让你可以在纯函数里声明"我需要做某个有副作用的操作"(比如获取用户输入、读取全局状态),但不用关心这个操作具体怎么实现——具体的实现交给专门的"处理器(Handler)"来完成。

和 Monad 这类传统副作用处理方式比,它的优势在于:

  • 不需要把整个代码包裹在 Monad 的链式调用里,代码更接近普通的同步写法
  • 同一个操作意图可以被不同的处理器适配,比如开发环境用模拟数据,生产环境用真实接口

用 JavaScript 模拟 Algebraic Effects

JavaScript 原生没有内置 Algebraic Effects,但我们可以用**生成器函数(Generator)**来模拟核心逻辑——生成器的暂停/恢复特性刚好对应 Effect 的"抛出请求"和"处理后继续执行"。

第一步:定义 Effect 和 Handler 基础机制

先写一个简单的工具函数,用来捕获生成器里抛出的 Effect 请求,然后交给对应的 Handler 处理:

// 处理生成器函数与对应Effect处理器的核心逻辑
function runWithHandler(generator, handlers) {
  const iterator = generator();

  function handle(result) {
    if (result.done) return Promise.resolve(result.value);

    // 识别并处理Effect请求
    if (result.value.type && handlers[result.value.type]) {
      return Promise.resolve(handlers[result.value.type](result.value.payload))
        .then(response => handle(iterator.next(response)))
        .catch(error => handle(iterator.throw(error)));
    }

    // 处理普通yield值
    return handle(iterator.next(result.value));
  }

  return handle(iterator.next());
}

// 辅助函数:创建标准化的Effect请求
function createEffect(type, payload) {
  return { type, payload };
}

第二步:声明带 Effect 的业务函数

比如我们写一个问候用户的函数,它只声明"需要获取用户名字"这个意图,完全不关心输入的来源:

function* greetUser() {
  // 抛出"获取用户输入"的Effect请求,仅传递提示文本
  const userName = yield createEffect('USER_INPUT', { prompt: '请输入你的名字:' });
  // 纯逻辑:根据输入生成问候语
  return `你好,${userName}!`;
}

第三步:为 Effect 编写不同的处理器

现在我们可以给USER_INPUT这个Effect编写不同的实现,适配不同场景:

场景1:浏览器环境用弹窗获取输入

const browserHandlers = {
  USER_INPUT: ({ prompt }) => {
    return prompt(prompt); // 调用浏览器原生弹窗函数
  }
};

// 运行函数
runWithHandler(greetUser, browserHandlers).then(console.log);
// 浏览器中执行时,会弹出输入框,输入名字后控制台将打印问候语

场景2:测试环境用模拟数据

const testHandlers = {
  USER_INPUT: () => {
    return '测试用户'; // 直接返回预设模拟数据,无需真实交互
  }
};

// 测试时运行
runWithHandler(greetUser, testHandlers).then(console.log);
// 控制台直接输出:你好,测试用户!

核心逻辑说明

  • 生成器函数greetUser里的yield createEffect(...)是在"抛出"一个Effect请求,此时函数会暂停执行。
  • runWithHandler捕获这个请求后,找到对应的Handler处理,拿到结果后用iterator.next(response)恢复生成器执行,把结果传递给userName变量。
  • 这就实现了意图与实现的完全分离:业务逻辑只关心"需要什么",具体怎么获取由外部Handler决定。

内容的提问来源于stack exchange,提问作者SmallTown NE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:12:16