使用ramda在JS中进行Pointfree递归

时间:2016-12-05 23:11:15

标签: javascript recursion functional-programming pointfree ramda.js

我正在学习无点函数,并试图以该样式实现这个递归空删除器。

可以使用,但是不是无点:

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

以下是我对此无效的尝试:

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
)

2 个答案:

答案 0 :(得分:14)

幸运的是,JavaScript有资源来处理其缺乏懒惰的问题。因此,完全可以通过以下方式使用lambda函数来声明递归无点解决方案:a => f(a)。只需将R.map(removeNull)替换为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
)

在您的情况下,我建议您使用R.reject,这是R.filter的对话。由于您否定谓词,R.filter(R.pipe(R.isNil, R.not))等于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
)

最后,此函数具有以下结构ifElse(predicate, whenTrue, identity),它等于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))
    )
)

简化版,关于Declan Whelan的评论,因为数组是Object

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

答案 1 :(得分:3)

Javascript缺乏懒惰是一个双重杀手: 你不能在它的const时调用它,因为你在同一个范围内并试图在其定义中解析resolveNulls。

另外,你不能只映射(recurseAction(action)),因为定义本身会破坏堆栈,所以你需要将它包装在另一个范围内:

const {ifElse, always, tap, apply, either, is, isNil, not, pipe, filter, map, identity} = require('ramda')

const filterNotNull = filter(pipe(isNil, not))
const log = tap(console.log)

const recurseAction =
  action =>
    ifElse(
      either(is(Array), is(Object)),
      pipe(
        action,
        map(a => recurseAction(action)(a))
      ),
      identity
    )

const removeNulls = recurseAction(filterNotNull)

const a = {
  a: null,
  b: "blah",
  c: 2,
  d: undefined,
  e: {
    meow: null,
    blah: undefined,
    jim: 'bob'
  }
}

const b = removeNulls(a)
console.log(b)