在过去的几天里,我研究了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性能优势的确切原因。我是对的吗?
答案 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);
在这个例子中(假设我没有做过任何可怕的错别字),那么我们不需要评估除了参数之外的任何其他内容,也不需要进行递归调用。