如何使用 Ramda 编写 point-free 函数式 JS

How to write point-free functional JS using Ramda

我有一个对象数组

const myNumbers = [
  {
   top: 10,
   bottom: 5,
   rate: 5
  },
  {
   top: 9,
   bottom: 4,
   rate: 3
  },
];

我想 运行 一些函数,让这些数字在我对它们做任何事情之前可用;

const addTen = r.add(10);
const double = r.multiply(2);

还有一个接受数字并做一些数学运算的函数:

const process = (top, bottom, rate) => r.multiply(r.subtract(bottom, top), rate)

所以我的最终函数看起来像

muNymbers.map(({ top, bottom, rate }) =>
  process(addTen(top), double(bottom), rate)
);

光是看这段代码就可以看出,这两个函数已经嵌套得很深,不是特别清晰。我真正的问题再次稍微复杂一些,我正在努力了解如何在为不同的操作选择不同的值时使这一点变得免费。

这里是一个免点的方法。您要查找的主要函数是 pipeevolveconverge。我不确定这是否是最好的方式,这是我能想到的最好的方式:

const { add, converge, evolve, map, multiply, pipe, prop, subtract } = R;

const myNumbers = [
    { top: 10, bottom: 5, rate: 5 },
    { top: 9, bottom: 4, rate: 3 },
];

const process = pipe(

    evolve({
        top: add(10),
        bottom: multiply(2),
    }),

    converge(multiply, [

        converge(subtract, [
            prop('bottom'),
            prop('top'),
        ]),

        prop('rate'),
    ]),
);

console.log(map(process, myNumbers));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

如果这是编写无点代码的练习,@JeffreyWesterkamp 的解决方案就可以了。

但是,对于生产代码,任何无点解决方案的可读性都将比这个简单版本很多差:

const process = ({top, bottom, rate}) => ((2 * bottom) - (10 + top)) * rate;

const myNumbers = [
    { top: 10, bottom: 5, rate: 5 },
    { top: 9, bottom: 4, rate: 3 },
];

console.log(R.map(process, myNumbers));
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>

关键是不要迷恋无积分。它是一种有时使代码更易于阅读、更易于理解的工具。但如果不这样做,就不值得使用。

不要误会我的意思。我是无点代码的忠实拥护者,Ramda(免责声明:我是它的作者之一)有一些有用的工具可以帮助您编写它。但 Ramda 与其他代码一起工作得很好。所以请明智地使用它。


另外一点(咳咳):Ramda 提供了两个相当不寻常的函数,useWithconverge,使编写无点代码变得更容易。但是 converge 通常可以被更标准的 lift 代替。它不能总是被替换,因为它有一些 lift 不提供的处理可变函数的特性,但是当你可以使用 lift 时,我建议你这样做。例如,而不是

converge(subtract, [prop('bottom'), prop('top')])

你可能会写

lift(subtract)(prop('bottom'), prop('top'))

据我所知,没有 useWith 的标准替代品。但我会尽可能用 lift 替换 converge