如何防止尾部递归函数反转列表的顺序?

用户名

我正在尝试功能List类型和结构共享。由于Javascript没有尾递归模块约束优化,因此我们不能只写这样的List组合器,因为它们不是堆栈安全的:

const list =
  [1, [2, [3, [4, [5, []]]]]];


const take = n => ([head, tail]) =>
  n === 0 ? []
    : head === undefined ? []
    : [head, take(n - 1) (tail)];


console.log(
  take(3) (list) // [1, [2, [3, []]]]
);

现在,我尝试take递归地实现tail,以便可以依靠TCO(PromiseEcmascript中仍未解决)或使用蹦床(在示例中为使事情简单而省略):

const list =
  [1, [2, [3, [4, [5, []]]]]];


const safeTake = n => list => {
  const aux = (n, acc, [head, tail]) => n === 0 ? acc
    : head === undefined ? acc
    : aux(n - 1, [head, acc], tail);

  return aux(n, [], list);
};


console.log(
  safeTake(3) (list) // [3, [2, [1, []]]]
);

这可以工作,但是新创建的列表的顺序相反。我该如何以纯粹的功能方式解决此问题?

阿迪特·沙

懒惰为您免费提供尾部递归模态缺点。因此,显而易见的解决方案是使用thunk。但是,我们不只是想要任何类型的重击。我们想要一个笨拙的头部正常形式的表情在JavaScript中,我们可以使用惰性获取器实现此目标,如下所示:

const cons = (head, tail) => ({ head, tail });

const list = cons(1, cons(2, cons(3, cons(4, cons(5, null)))));

const take = n => n === 0 ? xs => null : xs => xs && {
    head: xs.head,
    get tail() {
        delete this.tail;
        return this.tail = take(n - 1)(xs.tail);
    }
};

console.log(take(3)(list));

使用惰性获取器有很多优点:

  1. 正常属性和惰性属性以相同的方式使用。
  2. 您可以使用它来创建无限的数据结构。
  3. 您不必担心炸毁堆栈。

希望能有所帮助。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章