LazyEvaluation的性能优势究竟出在哪里?

时间:2013-07-18 05:30:53

标签: javascript haskell functional-programming lazy-evaluation

在过去的几天里,我研究了LazyEvaluation,主要是在性能方面,想知道 LazyEvalutaion的性能优势出现在哪里

我一直不清楚阅读各种文章,但很少包括

What are the advantages of Lazy Evaluation?

  

这指的是语法树的评估。如果你评价一个   语法树懒惰(即,当它代表的值是需要的时候),你   必须通过你的计算的前面步骤进行   整体。这是懒惰评估的开销。但是,有   两个优点。 1)如果没有,你将不会不必要地评估树   结果从未使用

例如,JavaScript实现了 if 语法。

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

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

要完成评估,在语法树中忽略不评估。

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

  

function 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评估策略评估函数(参数)必然性, if - else - 不评估控件不再有效, tak功能的评估步数会爆炸。

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

除了无限列表,我理解这是LazyEvaluation性能优势的确切原因。我是对的吗?

1 个答案:

答案 0 :(得分:3)

我认为你有正确的想法。

我认为你不需要所有的复杂性。想象一下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);

在这个例子中(假设我没有做过任何可怕的错别字),那么我们不需要评估除了参数之外的任何其他内容,也不需要进行递归调用。