用确定性值替换重复的函数应用程序

时间:2015-03-05 16:48:50

标签: haskell

f x y z = [n | n <- z, n > x + y]

f 1 2 [3,4]

x + y首先只执行一次,以便后续调用被value 3代替? GHC Haskell对FP的这项工作进行了优化,为我们带来了参考透明度的优点吗?

如何追踪证明呢?

2 个答案:

答案 0 :(得分:9)

认为计算出的值将被重用。

这种事情的一般问题是,x + y很便宜,但你可以在那里进行一些操作,产生一个完全浩大的结果,你可能不想要留在记忆中。这是一种冗长的说法,“这是时间/空间的权衡”。

正因如此,似乎GHC倾向于重复工作,以防丢失的空间无法弥补所获得的时间。

确定的方法是在编译代码时要求GHC转储Core。然后,您可以准确地看到将要执行的内容。 (尽量准备它非常详细!)哦,并确保你打开优化! (即-O2标志。)

如果您将功能改为

f x y z = let s = x + y in [ n | n <- z, n > s ]

现在s 肯定只执行一次。 (即,每次拨打f一次。每次拨打f时,它仍会重新计算s。)

顺便提一下,如果您对保存整个函数的已计算结果感兴趣,那么您正在寻找的搜索词是“memoisation”。

答案 1 :(得分:6)

将会发生什么取决于您是使用ghci还是ghc然后,如果您正在编译代码,那么正在使用什么优化级别。

以下是测试评估的一种方法:

import Debug.Trace

f x y z = [n | n <- z, n > tx x + ty y]
  where tx = trace "x"
        ty = trace "y"

main = print $ f 1 2 [3,4]

使用7.8.3我得到以下结果:

  1. ghci:x y x y [4]
  2. ghc(无优化):x y x y [4]
  3. ghc -O2:x y [4]
  4. 添加trace调用可能会影响CSE优化。但这确实表明-O2会将x+y提升出循环。