1

最近在codewars上做一些JS任务,遇到了这个任务Tail recursion with trampoline。这里我们需要创建 thunk 函数和 trampoline 函数来摆脱恼人的 RangeError: Maximum call stack size exceeded。所以我尝试了这段代码:

function thunk(fn) { 
  let args = [...arguments].slice(1, arguments.length);
  return function () { 
    return fn.apply(null, args);
  };
};

function trampoline(thunk) {
  while (typeof thunk === 'function') {
    thunk = thunk();
  }
  return thunk; 
}

function isEven(n) {
  let arg = n;

  function _isEven() {
    return (arg === 0 ? true : isOdd(arg - 1));
  };

  return trampoline(thunk(_isEven, n));
}

function isOdd(n) {
  let arg = n;

  function _isOdd() {
    return (arg === 0 ? false : isEven(arg - 1));
  };

  return trampoline(thunk(_isOdd, n));
}

这没有用,仍然有 RangeError。但是在我将 console.log() 添加到 _isOdd 或 _isEven 之后,它不会抛出错误并通过所有测试。像这样:

function thunk(fn) { 
  let args = [...arguments].slice(1, arguments.length);
  return function () { 
    return fn.apply(null, args);
  };
};

function trampoline(thunk) {
  while (typeof thunk === 'function') {
    thunk = thunk();
  }
  return thunk; 
}

function isEven(n) {
  let arg = n;

  function _isEven() {
    console.log();
    return (arg === 0 ? true : isOdd(arg - 1));
  };

  return trampoline(thunk(_isEven, n));
}

function isOdd(n) {
  let arg = n;

  function _isOdd() {
    return (arg === 0 ? false : isEven(arg - 1));
  };

  return trampoline(thunk(_isOdd, n));
}

我理解错误并重写了代码,但不明白为什么添加console.log()时它会起作用。

4

1 回答 1

0

此任务的正确解决方案如下:

function thunk(fn /*, args */) {
  return fn.bind.apply(fn, arguments);
}


function trampoline(thunk) {
  while(typeof (thunk=thunk()) == "function");
  return thunk;
}

function _isOdd(n) {
  return (n === 0 ? false : thunk(_isEven, n - 1));
}
function _isEven(n) {
  return (n === 0 ? true : thunk(_isOdd, n - 1));
}
function isEven(n) {
  return trampoline(thunk(_isEven, n));
}

function isOdd(n) {
  return trampoline(thunk(_isOdd, n));
}

于 2020-11-21T21:48:48.183 回答