如何将这个大阶乘函数转换为高阶函数?

How can I convert this large factorial function to a higher-order function?

以下代码在 factorial 函数之外使用了一个 cache 对象。 factorial 函数本身很大,有太多关于查找阶乘和缓存的问题。

如何将此代码转换为高阶函数并在调用

时生成相同的结果
console.log(factorial(5));
console.log(factorial(7));

cache = { }

function factorial(n) {
  
  if (n === 0) {
    return 1;
  }
  
  if (cache[n])
  {
    return cache[n];
  }
  
  console.log("Stack Up: " + n);
  
  var value = n * factorial(n - 1);
  
  console.log("Stack Down: " + value);
  
  cache[n] = value;
  
  return value;
}

console.log(factorial(5));
console.log(factorial(7));

已经有 other answers out there for memoising recursive functions,但我会在 javascript 中将该答案调整为阶乘,以便您可以更轻松地了解它的工作原理

编写记忆递归函数的秘诀是延续传递风格。当您想使非尾递归函数堆栈安全时,可以使用类似的技术。

我将在第一个示例中留下一些 console.log 语句,以便您可以看到它何时实际计算以及何时仅进行备忘录查找。

const memoise = f => {
  const memo = new Map()
  const compute = (x, k) =>
    (console.log('compute', x),
    memo.get(x, memo.set(x, f(x,k))))
  const lookup = x =>
    (console.log('lookup', x),
    memo.has(x) ? memo.get(x) : compute(x, lookup))
  return lookup
}

const factk = (x, k) => {
  if (x === 0)
    return 1
  else
    return x * k(x - 1)
}

const memfact = memoise(factk)

console.log(memfact(5)) // 120
console.log(memfact(7)) // 5040


在这里,我删除了 memoise 内的 console.log 调用,而是演示了一个记忆的斐波那契函数与一个未记忆的斐波那契函数。比较 memoise(fibk)badfib

之间的戏剧性时间差异

const memoise = f => {
  const memo = new Map()
  const compute = (x, k) =>
    memo.get(x, memo.set(x, f(x,k)))
  const lookup = x =>
    memo.has(x) ? memo.get(x) : compute(x, lookup)
  return lookup
}

const fibk = (x, k) => {
  if (x < 2)
    return x
  else
    return k(x - 1) + k(x - 2)
}

const badfib = x => {
  if (x < 2)
    return x
  else
    return badfib(x - 1) + badfib(x - 2)
}

console.time('memoised')
console.log(memoise (fibk) (35)) // 9227465 1.46ms
console.timeEnd('memoised')

console.time('unmemoised')
console.log(badfib(35))          // 9227465 135.85ms
console.timeEnd('unmemoised')