【发布时间】:2021-04-06 14:50:37
【问题描述】:
假设我们想通过使用 lambdas 作为代表我们想要添加新数据的位置的“洞”来构建大型结构。例如,这里我们使用这个想法构建[0,[1,[2,null]]]:
builder_0 = hole => hole; // hole => hole;
builder_1 = hole => builder_0([0,hole]); // hole => [0, hole];
builder_2 = hole => builder_1([1,hole]); // hole => [0, [1, hole]];
builder_3 = hole => builder_2([2,hole]); // hole => [0, [1, [2, hole]]];
// prints [0,[1,[2,null]]], but will stack overflows if too many lines
console.log(JSON.stringify(builder_3(null)));
这很好用。我们也可以循环执行:
let builder = hole => hole;
for (let i = 0; i < 1000; ++i) {
let last_builder = builder;
builder = hole => last_builder([i, hole]);
};
console.log(builder(null));
这也有效,但如果限制大于10000,此算法将堆栈溢出。问题是,由于last_builder([i,hole]) 没有在hole => ... 闭包内进行评估,它会构建大量未评估的lambdas,这些lambdas 将迅速消耗整个堆栈。请注意,[0,[1,[2,null]]] 只是一个无用的示例,JavaScript 将无法使用上述基于孔的技术构建任何大型结构(想想树、JSON、不可变容器等)。
尾调用优化和蹦床在这里无济于事,因为我们甚至没有一开始的递归函数。有没有什么巧妙的技巧可以让这种函数式成语在没有堆栈溢出的情况下工作?
【问题讨论】:
-
为什么不将每个 lambda 推入数组,而不是拥有 10,000 个嵌套数组,每个数组只有一个整数和另一个数组?我不明白这个数据结构的目的。
-
第一个 sn-p 的前两行足以说明问题,然后是第一个 sn-p 的最后一行。在第 2 行中,构建器已被重新定义为自称 ad infinitum。没有终止呼叫的终止条件。
-
@MaiaVictor 我不知道你为什么会告诉我我错了,当我使用我指出的行在浏览器控制台中展示问题时。
-
我说“我说的不是你的要点。”
-
@Amy Jesus,我需要眼镜。所以,是的,你是对的,我的问题上的 sn-p 是错误的。我修复了它以正确演示该问题。感谢您指出错误。
标签: javascript functional-programming stack-overflow