【发布时间】:2023-04-08 14:02:02
【问题描述】:
我正在尝试函数式List 类型和结构共享。由于 Javascript 没有 Tail Recursive Modulo Cons 优化,我们不能像这样写 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(在 Ecmascript 中仍然是一个不稳定的Promise),也可以使用蹦床(为了简单起见,示例中省略了):
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, []]]]
);
这可行,但新创建的列表顺序相反。如何以纯粹的功能方式解决此问题?
【问题讨论】:
-
您是否要求明确实现“尾调用模数”实现?
-
最简单的解决方案是来自
safeTake的return reverse(aux(n, [], list))。 -
@Bergi 我昨天在another question 上询问了一个明确的TRMC。
-
@Bergi 我个人认为缺少 TRMC 是 JS 的最大缺点之一(更不用说 TCO)。但是话又说回来,我不知道任何实现这种优化的动态语言。
-
JS 无论如何都没有不可变的链表,所以它几乎不需要 TRMC。我猜你真的想改用 PureScript :-)
标签: javascript recursion functional-programming tail-recursion