Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/449.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 尾部调用优化递归函数_Javascript_Tail Recursion - Fatal编程技术网

Javascript 尾部调用优化递归函数

Javascript 尾部调用优化递归函数,javascript,tail-recursion,Javascript,Tail Recursion,这是一个函数,它可以将数组深度展平 const deepFlatten = (input) => { let result = []; input.forEach((val, index) => { if (Array.isArray(val)) { result.push(...deepFlatten(val)); } else { result.push(val); } }); return result; };

这是一个函数,它可以将数组深度展平

const deepFlatten = (input) => {
  let result = [];
  input.forEach((val, index) => {
    if (Array.isArray(val)) {
      result.push(...deepFlatten(val));
    } else {
      result.push(val);
    }
  });
  return result;
};
在一次讨论中,有人告诉我这不是内存效率,因为它可能会导致堆栈溢出

我在书中读到,我可以潜在地重新编写它,使其成为TCO-ed


如果递归调用位于forEach内部,则无法对其进行优化,因为为了应用TCO,编译器需要检查您是否未保存上一次调用的“状态”。如果是
forEach
,则保存当前位置的“状态”

为了用TCO实现它,您可以重写要用递归调用实现的
foreach
,它看起来像这样:

功能控制TCO(输入){
const helper=(第一个、剩余、结果)=>{
如果(!Array.isArray(第一个)){
结果:推(第一);
如果(rest.length>0){
返回助手(rest,[],result);
}否则{
返回结果;
}
}否则{
常量[newFirst,…newRest]=第一个.concat(rest);
返回帮助程序(newFirst、newRest、result);
}
};
返回帮助程序(输入,[],[]);
}
控制台日志(TCO)([
[1], 2, [3], 4, [5, 6, [7]]

]));递归函数表达优雅,尾部递归优化甚至可以防止它们破坏堆栈

然而,任何递归函数都可以转换为更丑陋的基于迭代器的解决方案,这可能只是因为它的内存消耗和性能很好,尽管不值得一看

见:


也许这是对不同方法的测试:

一般的尾部调用

我有;我认为这个答案显示了解决这个特定问题的更好方法,但并不是所有函数都能被很好地分解。这个答案将关注递归函数中的尾部调用,以及一般的尾部调用

通常,要将重复调用移动到尾部位置,将创建一个辅助函数(
aux
),其中函数的参数包含完成该计算步骤所需的所有状态

const flattedeep=arr=>
{
常数aux=(acc,[x,…xs])=>
x==未定义
?acc
:Array.isArray(x)
?辅助(附件,x.concat(xs))
:辅助(附件concat(x),xs)
返回辅助([],arr)
}
常数数据=
[0, [1, [2, 3, 4], 5, 6], [7, 8, [9]]]
console.log(数据)

//[0,1,2,3,4,5,6,7,8,9]
不确定是否只是建议
var deepflant(input)=>input.reduce((a,b)=>!Array.isArray(b)?a.concat(b):a.concat(deepflant(b)),[])
要测量内存使用情况,我只需要设置一个条件断点。e、 g.
deepflant([1,[2,[3,[4,5]]])
然后在val==5的情况下设置一个断点,然后查看调用堆栈有多深如果您详细阐述一下,并将其添加为答案,它肯定至少会得到支持!不,你应该再和你的讨论搭档谈谈。这不会因为其递归性而导致堆栈溢出。@Bergi为什么会导致堆栈溢出?我知道这不是我最初的问题,但这个解决方案不会创建许多中间数组吗?您还可以解释一下rest参数的用途吗?是的,rest参数用于保存以前调用的“状态”…将每种类型的递归函数转换为TCO递归函数的常见做法是传递“计算状态”这是一个典型的例子:你有没有自动化的工具来测量一个函数的内存使用情况?(我想是开发工具吧?)!你正在使用解构和广泛传播,这对我来说有点难读,但肯定很有趣。upvoting@GeorgeKatsanos关于这个话题有很多东西要写,我想把这个答案放在一起太久了——只是,我必须上床睡觉了!我把剩下的留作草稿,明天完成^^