12

考虑这个函数:

f as = if length as > 100 then length as else 100

由于该函数是纯函数,因此很明显两个调用的长度相同。我的问题是 Haskell 优化器是否将上面的代码转换为以下代码?

f as = 
  let l = length as
  in if l > 100 then l else 100

如果是这样,那么哪个级别设置启用它?如果没有,那为什么?在这种情况下,内存浪费不是这个答案中解释的原因,因为一旦函数执行完成,引入的变量就会被释放。


请注意,由于本地范围,这不是此问题的重复,因此它可能会得到完全不同的答案。

4

3 回答 3

16

GHC 现在默认做一些 CSE,因为-fcse标志是打开的。

默认情况下打开.. 启用公共子表达式消除优化。如果您有一些不希望通用的 unsafePerformIO 表达式,则将其关闭会很有用。

然而,由于引入共享的问题(因此空间泄漏) ,它是保守的。不过,CSE 通行证变得更好了(还有这个)。

最后,请注意有一个完整的 CSE 插件。

如果您有可以从中受益的代码。

于 2013-02-26T09:16:53.023 回答
13

即使在这样的本地环境下,引入共享始终是一种优化的情况仍然不明显。考虑这个示例定义

f = if length [1 .. 1000000] > 0 then head [1 .. 1000000] else 0

对比这个

f = let xs = [1 .. 1000000] in if length xs > 0 then head xs else 0

你会发现在这种情况下,第一个表现得更好,因为对列表执行的每个计算都很便宜,而第二个版本将导致列表在内存中完全展开length,并且只能被丢弃head减少后。

于 2013-02-26T08:13:35.640 回答
5

您所描述的情况更多地与常见的子表达式消除有关,而不是记忆,但是GHC 目前似乎也没有这样做,因为无意的共享可能会导致空间泄漏。

于 2013-02-26T08:57:36.843 回答