Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement using point-free recursion to remove null values in objects using Ramda?

I am learning about pointfree functions and am trying to implement this recursive null remover in that style.

Works, but is not pointfree:

function removeNulls(obj) {
  return R.ifElse(
    R.either(R.is(Array), R.is(Object)),
    R.pipe(
      R.filter(R.pipe(R.isNil, R.not)),
      R.map(removeNulls)
    ),
    R.identity
  )(obj)
}

module.exports = removeNulls

The following is my non-functioning attempt at it:

const removeNulls = R.ifElse(
  R.either(R.is(Array), R.is(Object)),
  R.pipe(
    R.filter(R.pipe(R.isNil, R.not)),
    // throws `ReferenceError: removeNulls is not defined`
    R.map(removeNulls)
  ),
  R.identity
)
like image 685
Henry Marshall Avatar asked Dec 05 '16 23:12

Henry Marshall


1 Answers

Luckily JavaScript has resources to deal with its lack of laziness. So, it's completely possible to declare a recursive pointfree solution by using lambda functions in the following way: a => f(a). Just replace R.map(removeNull) with R.map(a => removeNull(a)).

const removeNulls = R.ifElse(
    R.either(R.is(Array), R.is(Object)),
    R.pipe(
        R.filter(R.pipe(R.isNil, R.not)),
        R.map(a => removeNulls(a))
    ),
    R.identity
)

In your case, I'll recommend you to use R.reject which is the oposite to R.filter. Since you are negating the predicate, R.filter(R.pipe(R.isNil, R.not)) is equal to R.reject(R.isNil)

const removeNulls = R.ifElse(
    R.either(R.is(Array), R.is(Object)),
    R.pipe(
        R.reject(R.isNil),
        R.map(a => removeNulls(a))
    ),
    R.identity
)

Finally, this function has the following structure ifElse(predicate, whenTrue, identity) which is equal to when(predicate, whenTrue)

const removeNulls = R.when(
    R.either(R.is(Array), R.is(Object)),
    R.pipe(
        R.reject(R.isNil),
        R.map(a => removeNulls(a))
    )
)

Simplified version, regarding the comment from Declan Whelan, since arrays are Object

const removeNulls = R.when(
    R.is(Object),
    R.pipe(
        R.reject(R.isNil),
        R.map(a => removeNulls(a))
    )
)
like image 102
yosbel Avatar answered Oct 12 '22 11:10

yosbel