← 中文资源

简体中文版本

Ramda 组合式数据管道

用 Ramda 的 compose、镜头与柯里化谓词构建无副作用的数据变换管道:每个环节可独立测试,整体按声明顺序组合。

阅读英文原文

示例说明

数据清洗逻辑写成嵌套回调后难以单测与复用。Ramda 的 compose 从右向左组合纯函数,每个环节只做一件事;lens 让对嵌套结构的更新也是不可变的——返回新对象而非原地修改;curry 把多参函数拆成可部分应用的函数,便于把参数配置与数据处理分离。

技术要点

  • compose 从右向左声明处理顺序
  • lensPath 实现不可变的嵌套字段更新
  • curry 支持先绑定系数再复用变换

代码解读

summarize 管道依次执行:过滤已支付订单、给每单叠加一成忠诚度加成、按总额降序排序、抽取客户名。applyLoyalty 用 curry 固定加成率后成为单参变换函数。raise 演示两段式调用:先给加价额得到新函数,再应用到具体订单,返回的是包含更新后 total 的新对象。

使用建议

compose 的执行顺序是声明顺序的反向,团队习惯从左到右时可换 pipe。纯函数管道便于用样例数据做表驱动测试。避免为了函数式而函数式,简单场景用普通方法链更直白。

代码示例

import { compose, map, filter, prop, sortBy, descend, lensPath, over, add, curry } from 'ramda';

const orders = [
  { id: 1, customer: 'ada', total: 120, status: 'paid' },
  { id: 2, customer: 'grace', total: 85, status: 'refunded' },
  { id: 3, customer: 'ada', total: 340, status: 'paid' },
];

const applyLoyalty = curry((rate, order) =>
  over(lensPath(['total']), add(Math.round(order.total * rate)), order),
);

const summarize = compose(
  map(prop('customer')),
  sortBy(descend(prop('total'))),
  map(applyLoyalty(0.1)),
  filter((o) => o.status === 'paid'),
);

console.log(summarize(orders));

const raise = curry((amount, order) =>
  over(lensPath(['total']), add(amount), order),
);
console.log(raise(5)(orders[0]));