为什么 Haskell 不能优化这个重复的函数调用?

Cif*_*gum 7 haskell

在我的 Haskell 代码中,我使用了一个经常被调用的函数,如下所示:

doSomething x y = (a, b)
where a = expensive1 x y
      b = expensive2 x y a
Run Code Online (Sandbox Code Playgroud)

使用 GHC 8.10.3 和 -O2 编译我的程序需要大约 45 秒才能运行。但是,如果我像这样编写相同的函数:

doSomething x y = (a, b)
where a = expensive1 x y
      b = expensive2 x y (expensive1 x y)
Run Code Online (Sandbox Code Playgroud)

我的程序需要大约 60 秒才能运行。

编译器不应该识别重复的调用expensive1 x y并将其优化掉吗?expensive1并且expensive2是纯函数,因此expensive1 x y不需要重新计算。或者 GC 是否过于激进和垃圾收集,a之后才b需要?

Dan*_*ner 8

这是一种权衡。您建议的优化减少了运行时间,但增加了内存使用量。每次都自动获得正确的权衡太难了,所以程序员可以控制它——命名一个东西,它被共享,不命名,它被重新计算。

(...主要是。与这些事情一样,这很复杂。但这是答案的 10 公里视图。)

顺便说一下,这种优化的名称是“公共子表达式消除”。谷歌搜索应该会为您提供有关该领域中不同编译器选择的更多信息。

  • @oisdk是的,但它对此非常保守,正是因为正如答案中所说,它实际上可能会产生有害的记忆影响。(除了增加编译时间外,完整的通用 CSE 还需要解决停止问题,你只能得到启发式方法。) (3认同)
  • @oisdk 正如我在答案中所说......这很复杂。^_^ (3认同)