【问题标题】:Does Haskell optimizer utilize memoization for repeated function calls in a scope?Haskell 优化器是否利用 memoization 在范围内重复调用函数?
【发布时间】:2013-02-11 14:40:34
【问题描述】:

考虑这个函数:

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

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


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

【问题讨论】:

    标签: haskell optimization compiler-construction memoization


    【解决方案1】:

    GHC 现在执行some CSE by default,因为-fcse 标志已打开。

    默认开启.. 启用公共子表达式消除 优化。如果你有一些,关闭它会很有用 不希望通用的 unsafePerformIO 表达式。

    但是,它是conservative,由于引入共享的问题(因此空间泄漏)。 CSE 通行证获得了bit better(和this)。

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

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

    【讨论】:

      【解决方案2】:

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

      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被减少后才能丢弃。

      【讨论】:

      • 尽管存在这个问题,但 ghc 可能对 CSE 更具攻击性。你只需要对你的 CSE 价值有一个大小估计。一个简单的估计是基本类型占用的空间可以忽略不计。
      • length [1 .. 1000000] > 0 怎么算便宜?在评估“>”之前,“长度”是否必须返回? (在 ghci 中,当我增加列表的大小时,操作会明显变慢)
      • @salty-horse 在空间方面便宜:恒定空间,线性时间。
      【解决方案3】:

      您所描述的情况与common subexpression elimination 的关系比记忆化更多,但似乎GHC currently doesn't do that either 因为无意的共享可能导致空间泄漏。

      【讨论】:

        猜你喜欢
        • 2017-06-26
        • 1970-01-01
        • 2011-08-30
        • 2011-03-31
        • 1970-01-01
        • 2020-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多