简体   繁体   中英

How to write point-free functional JS using Ramda

I have an array of objects

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

I want to run a few functions that make the numbers usable before I do anything with them;

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

And a function that accepts the numbers and does some maths:

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

So my final function looks like

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

Just looking at this code you can see both functions are already becoming very nested and not particularly clear. My real problem is slightly more complicated again, and I am struggling to see how I can make this point-free when picking different values for different operations.

Here is a point-free approach. The main functions you're looking for are pipe , evolve and converge . I'm not sure if this is the best way, it's just the best I could think of:

 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> 

If this is an exercise in writing point-free code, a solution like the one from @JeffreyWesterkamp is fine.

For production code, though, any point-free solution is going to be a lot less readable than this simple version:

 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> 

The point is to not make a fetish over point-free. It is a tool that sometimes makes code easier to read, easier to understand. But it's not worth using if it doesn't do so.

Don't get me wrong. I'm a big fan of point-free code, and Ramda (disclaimer: I'm one of its authors) has some useful tools to help you write it. But Ramda works just fine with other code. So use it wisely.


One other point (ahem): Ramda supplies two fairly unusual functions, useWith and converge , to make it easier to write point-free code. But converge can often be replaced by the more standard lift . It can't always be replaced, as it has some features for handling variadic functions that lift does not supply, but when you can use lift , I would suggest that you do so. For instance, instead of

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

you might write

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

There's no standard replacement for useWith that I know of. But I would replace converge with lift whenever possible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM