4

这几天研究了LazyEvaluation,主要是在性能方面,想知道LazyEvalutaion的性能优势从何而来

阅读各种文章对我来说很不清楚,但很少有,包括

惰性评估的优点是什么?

这是指对语法树的评估。如果您懒惰地评估语法树(即,当需要它表示的值时),您必须将其完整地通过前面的计算步骤。这是惰性求值的开销。但是,有两个优点。1)如果从未使用过结果,您将不会不必要地评估树

例如,JavaScript 实现了if语法。

if(true)
{
    //to evaluate
}
else
{
    //not to evaluate
}

在这种普通情况下,我们没有任何性能问题。

待评估已完成,未评估在语法树中被忽略。

但是,在某些递归循环中,例如,Tak 函数 AKA Tarai 函数

函数 tak(x,y,z){ 返回 (x <= y) ?y : tak(tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y)); }

由于 JS 的 Eager Evaluation 策略评估函数(参数)的必然性,因此if - else - not to beevaluate控制不再起作用,并且tak 函数的评估步骤数爆炸式增长。

针对 Eager Evaluation(JS 或其他语言)的这一缺点,Haskell 可以毫无问题地评估tak ,并且一些 JS 库(例如lazy.js)在需要递归列表管理的函数式编程等特定领域表现出色。

除了无限列表,我知道这是 LazyEvaluation 性能优势的确切原因。我对么?

4

1 回答 1

4

我认为你的想法是正确的。

我不认为你需要所有的复杂性。想象一下 JavaScript 是

if (veryExpensiveFunction()) {
  doThis();
} else {
  doThat();
}

现在想象一下veryExpensiveFunction实现了。

function veryExpensiveFunction() {
   return true || evenMoreExpensiveFunction();
}

如果 JavaScript 因为||是惰性的(仅在需要时评估第二个参数),这将很快返回(因为true是,嗯,真的!)。如果它被实施而不是像

function veryExpensiveFunction() {
  var a = true;
  var b = evenMoreExpensiveFunction(); // forces the evaluation

  return a || b;
}

这需要很长时间来评估,因为您不必要地评估了这些论点。现在想象||应用于每个函数(即惰性语言)的魔法,您可能可以想象惰性可能带来的性能优势。

在你的例子中

function tak(x,y,z){ return (x <= y) ? y : tak(tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y)); }

让我们想象一切都是懒惰的。

 var a = tak(1,2,3);

这没有任何作用(无需评估)。a未使用,因此不评估任何内容。

 var a = tak(1,2,3);
 console.log(a);

现在我们可以推动对tak. 在评估我们需要得到结果时,我们首先替换其中的值(用它们的参数替换变量)。然后我们评估条件,然后只评估我们需要的条件。

 console.log((1 <= 2) ? 2 : tak(tak(1-1, 2, 3), tak(2-1, 1, 3), tak(3-1, 1, 2));
 console.log(   true  ? 2 : tak(tak(1-1, 2, 3), tak(2-1, 1, 3), tak(3-1, 1, 2));
 console.log(2);

在这个例子中(假设我没有犯任何可怕的拼写错误),那么我们不需要评估除参数之外的任何其他内容,并且不进行递归调用。

于 2013-07-18T07:18:07.230 回答