简体   繁体   中英

Ramda Converting to Free-Point Style

I haven't really found a good resource for this sort of thing. Apologies in advance if this question has been asked, though I couldn't quite find the answer (perhaps due to a lack of knowing how to search.

I have this function. It's like R.prepend / R.append , but it shoves a value into the middle of a list instead.

const insertMiddle = (val, arr) => 
  R.insert(Math.floor(arr.length/2), val, arr);

I'm just learning functional programming, so I'm writing a program with as much free-point-style as possible. Even if that takes away from readability a bit, I just like to see it done. Bend my brain to start thinking functionally and seeing how to solve problems that way.

Here's what I've done:

const halfLength = R.compose(
  Math.floor,
  R.divide(R.__, 2),
  R.prop('length')
);

// ----
const insertMiddle = (val, arr) =>
  R.insert(halfLength(arr), val, arr);
// ---- OR
const insertMiddle = (val, arr) =>
  R.insert(halfLength(arr), val, R.identity(arr));

This of course isn't free-point yet.

Here is ostensibly the next step:

const insertMiddle = (val, arr) => 
  R.insert(R.__, val)(halfLength(arr), R.identity(arr));

Now if I can get (halfLength(arr), R.identity(arr)) to be point-free, I'll be left with a function that just needs val .


Am I going about this the right way? What happens next?

How does:

  • x => foo(bar(x), x) or
  • x => foo(bar(x),baz(x))

become point free?

The R.chain called with two functions - chain(f, g)(x) is the equivalent of f(g(x), x). If with change the order of the last two parameters of R.insert (value & array), we can use it to create insertMiddle :

 const { compose, divide, __, prop, curry, chain, insert } = R const halfLength = compose( Math.floor, divide(__, 2), prop('length') ) const flippedInsert = curry((idx, val, arr) => insert(idx, arr, val)) const insertMiddle = chain(flippedInsert, halfLength) const arr = [1, 2, 3, 4] const result = insertMiddle(arr)('*') console.log(result)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>

Ramda does offer tools to make it easier to write points-free code. And if you are just fiddling around, trying to see how they work, we can do all sorts of things with them. But I would reiterate that the goal should be understandable code. Use points-free when it helps with readability; skip it when it doesn't.

There are a few Ramda functions specifically designed for this. (Disclaimer: I'm a Ramda author.) useWith , converge , and nthArg are prominent among these.

We can use converge and nthArg to get this to work:

 const {compose, divide, __, prop, converge, insert, pipe, nthArg} = R const halfLength = compose ( Math.floor, divide (__, 2), prop ('length') ) const insertMiddle = converge (insert, [pipe (nthArg (1), halfLength), nthArg (0), nthArg (1)]) console.log (insertMiddle (42, [1, 2, 3, 4, 5, 6]))
 <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>

We could even go whole-hog and inline halfLength

const insertMiddle = converge (insert, [
  pipe (nthArg (1), prop ('length'), divide (__, 2), Math .floor), 
  nthArg (0), 
  nthArg (1)
])

Again, as a learning exercise, this is fine. But I find either of those a lot less readable than a simple function, using only a bit of Ramda:

const insertMiddle = (x, xs) =>
  insert ((xs .length >> 1), x, xs)

or a plain vanilla version:

const insertMiddle = (x, xs, mid = xs .length >> 1) =>
  [... xs .slice (0, mid), x, ... xs .slice (mid)]

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