折叠器没有崩溃并且工作得相当好

时间:2018-05-15 23:29:24

标签: javascript reduce fold

我想要一个类似于Haskell或lisp中的foldr的折叠器。我的foldr导致大型数组上的堆栈溢出,并且可能是因为堆栈上的大量挂起操作无法减少直到它遇到基本情况。您将如何优化我的折叠器,以便它适用于大型阵列。

const foldr = (f, acc, [x, ...xs]) => 
  (typeof x === 'undefined') 
  ? acc 
  : f (x, foldr (f, acc, xs))

foldr((x, acc) => x + acc, 0, [...Array(100000).keys()])

2 个答案:

答案 0 :(得分:3)

foldr差不多reduceRight

const flip = f => (a, b) => f(b, a)

const foldr = (f, acc, arr) =>
  arr.reduceRight(flip(f), acc)

如果您希望保留arr.reduceRight解包为您提供的任意迭代的支持,请将[...arr].reduceRight替换为[x, ...xs]



const flip = f => (a, b) => f(b, a)

const foldr = (f, acc, arr) =>
  arr.reduceRight(flip(f), acc)

console.log(foldr((x, acc) => x + acc, 0, [...Array(100000).keys()]))




答案 1 :(得分:1)

问题是JavaScript使用的默认类似列表的结构是可变数组(不是真正的类C数组,它们可能在内部实现为树),而像Haskell或Lisp这样的函数语言使用链表。您可以在恒定时间内获得第一个元素和链接列表的其余部分而不会发生突变。如果你想在JavaScript中做同样的事情(没有变异),你必须创建(分配)新数组来获得数组的其余部分。

然而,整个倍数可以用内部突变来实现。整个功能不会做任何外部突变:

const foldr = (f, initialValue, arr) => {
  let value = initialValue;

  for (let i = arr.length - 1; i >= 0; i--) {
    value = f(arr[i], value)
  }

  return value;
}