如何在递归函数中避免尾部和蹦床出现堆栈溢出?

时间:2020-06-13 09:53:37

标签: javascript recursion functional-programming

我编写程序以通过测验-https://www.codewars.com/kata/53d045892578b1be8b0001c4,但仍然不适用于大数字。我的错误在哪里?

function thunk(fn, n, ac) {
  return fn(n, ac);
}

function trampoline(arg) {
  // console.log(arg);
  if (typeof arg === "number") {
    return arg;
  } else {
    return trampoline(arg);
  }
}

function trampolineSum(n) {
  function _sum(n, ac) {
    if (n === 0) {
      return ac;
    } else {
      return thunk(_sum, n - 1, ac + n);
    }
  }

  return trampoline(thunk(_sum, n, 0));
}

console.log(trampolineSum(4444));
console.log(trampolineSum(44444));

2 个答案:

答案 0 :(得分:2)

代码被故意破坏并丢失了东西。尝试弄清楚。
Function.prototype.bind()

thunk(fn / *,args * /)是一个接收函数的函数,可能还会有一些要传递给函数并返回函数的参数。调用此返回的函数时,它将返回执行fnfunction的结果。在函数式编程中,重排是延迟的表达式(函数)。它的评估被推迟到真正需要的时候。

trampoline(thunk)是一个反复执行thunk 参数直到返回非函数值的函数。然后返回最后一个值。

function thunk(fn, n, ac) {
  return ???.bind(null, n, ac);
}

const trampoline = res => {
  I_WANT_TO_LOOP (typeof res === 'function') { res = res(); }
  return res;
}

function trampolineSum(n) {
  function _sum(n, ac) {
    if (n === 0) {
      return ac;
    } else {
      return thunk(_sum, n - 1, ac + n);
    }
  }

  return trampoline(thunk(_sum, n, 0));
}

console.log(trampolineSum(4444));
console.log(trampolineSum(44444));

答案 1 :(得分:1)

这是您原始代码的一小部分-

function thunk(fn, n, ac) {
  return [ thunk, _ => fn(n, ac) ]
}

function trampoline(r) {
  while (r && r[0] === thunk)
    r = r[1]()
  return r
}

function trampolineSum(n) {
  function _sum(n, ac) {
    if (n === 0) {
      return ac;
    } else {
      return thunk(_sum, n - 1, ac + n);
    }
  }

  return trampoline(thunk(_sum, n, 0));
}

console.log(trampolineSum(4444)) // 9876790
console.log(trampolineSum(44444)) // 987656790

考虑替代实现-

const recur = (...v) =>
  ({ recur, [Symbol.iterator]: _ => v.values() })

const loop = f =>
{ let r = f()
  while (r && r.recur === recur)
    r = f(...r)
  return r
}

const trampolineSum = n =>
  loop
    ( (m = n, ac = 0) =>
        m === 0
          ? ac
          : recur(m - 1, ac + m)
    )

console.log(trampolineSum(4444)) // 9876790
console.log(trampolineSum(44444)) // 987656790