完全的懒惰已经
repeatedly
demonstrated
至
cause
space
leaks .
为什么从 -O
开始完全懒惰向前?我发现自己不相信 SPJ 的 The Implementation of Functional Programming Languages 中的推理。 .声称是在
f = \y -> y + sqrt 4
sqrt 4
每次都不必要地重复 f
已输入,因此我们应该将其 float 到 lambda 之外。我同意在小范围内,但既然我们已经看到这种转变在大范围内会导致什么问题,我不认为这是值得的。在我看来,这种转换的好处可以单方面获得**,只需更改本地代码,想要它的程序员应该手动实现它。你能说服我吗?是
full-laziness
实际上真的有用吗?如果您能提供手动实现需要多边合作或非本地转换的示例,我将特别相信。** 与手动实现的内联和流融合等优化不同,需要模块之间的多边合作和非本地代码更改
最佳答案
至少有一种常见的情况是完全懒惰是“安全的”并且是一种优化。
g :: Int -> Int
g z = f (z+1)
where f 0 = 0
f y = 1 + f (y-1)
这真的意味着
g = \z -> let {f = ...} in f (z+1)
并且,以这种方式编译,将为 f
分配一个闭包在调用它之前。显然这很愚蠢,编译器应该将程序转换为g_f 0 = 0
g_f y = 1 + g_f (y-1)
g z = g_f (z+1)
无需分配即可调用
g_f
.令人高兴的是,完全的惰性转换正是这样做的。显然,程序员可以避免做出这些不依赖于顶级函数参数的本地定义,但这样的定义通常被认为是好的风格......
另一个例子:
h :: [Int] -> [Int]
h xs = map (+1) xs
在这种情况下,您可以只进行 eta reduce,但通常不能进行 eta reduce。并命名函数
(+1)
很丑。
关于haskell - 为什么完全惰性是默认优化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35115172/