为什么完全懒惰是默认优化? [英] Why is full-laziness a default optimization?
问题描述
为什么从 -O
以上完全懒惰?我发现自己不相信SPJ的执行函数式编程语言。要求是在
f = \y - > y + sqrt 4
sqrt 4
是不必要的在每次输入 f
时重复,所以我们应该将它浮动在lambda之外。我同意这种观点,但由于我们已经看到了这种转变在大规模中造成的问题,我不相信这是值得的。在我看来,这种转换的好处可以单方面获得**只需要本地代码更改和程序员就可以手动实现。
你能说服我吗?除此以外? 完全懒惰
其实真的很有用吗?我会特别相信,如果您能提供手动实施的例子,需要多边合作或非本地转换。
**与内嵌和流合并等优化不同手工实施需要模块和非本地代码更改之间的多边合作。至少有一种常见的情况是完全懒惰是安全并进行优化。
g :: Int - > Int
gz = f(z + 1)
其中f 0 = 0
fy = 1 + f(y-1)
这实际上意味着 g = \ z - >在f(z + 1)
中放置{f = ...},编译这种方式,在调用它之前将为 f
分配一个闭包。显然这很愚蠢,编译器应该将程序转换为
g_f 0 = 0
g_f y = 1 + g_f (y-1)
gz = g_f(z + 1)
调用 g_f
。令人高兴的是,完全懒惰转换完全就是这样。
显然,程序员可以避免使这些本地定义不依赖于顶级函数的参数,但是这样的定义一般认为是很好的风格... ...
另一个例子:
pre $ code $> h :: [Int] - > [Int]
h xs = map(+1)xs
在这种情况下,您可以埃塔减少,但通常你不能减少。并命名(+ 1)
函数是非常难看的。
Full laziness has been repeatedly demonstrated to cause space leaks.
Why is full laziness on from -O
onwards? I find myself unconvinced by the reasoning in SPJ's The Implementation of Functional Programming Languages. The claim is that in
f = \y -> y + sqrt 4
sqrt 4
is unnecessarily repeated each time f
is entered so we should float it outside the lambda. I agree in the small, but since we've seen what problems this transformation causes in the large I don't believe it is worth it. It seems to me that the benefits of this transformation are obtainable unilaterally** with only local code changes and programmers who want it should implement it by hand.
Can you convince me otherwise? Is full-laziness
actually really useful? I will be especially convinced if you can provide examples which to implement by hand require multilateral cooperation or non-local transformations.
** unlike optimizations like inlining and stream fusion which to implement by hand would require multilateral cooperation between modules and non-local code changes
There's at least one common case where full laziness is "safe" and an optimization.
g :: Int -> Int
g z = f (z+1)
where f 0 = 0
f y = 1 + f (y-1)
This really means g = \z -> let {f = ...} in f (z+1)
and, compiled that way, will allocate a closure for f
before calling it. Obviously that's silly, and the compiler should transform the program into
g_f 0 = 0
g_f y = 1 + g_f (y-1)
g z = g_f (z+1)
where no allocation is needed to call g_f
. Happily the full laziness transformation does exactly that.
Obviously programmers could refrain from making these local definitions that do not depend on the arguments of the top-level function, but such definitions are generally considered good style...
Another example:
h :: [Int] -> [Int]
h xs = map (+1) xs
In this case you can just eta reduce, but normally you can't eta reduce. And naming the function (+1)
is quite ugly.
这篇关于为什么完全懒惰是默认优化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!