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

Haskell 用确定性值替换重复函数应用程序,haskell,Haskell,fxyz=[n | nx+y] f 1 2[3,4] x+y是否一开始只执行一次,以便将连续调用替换为值3?GHCHaskell是否针对这项工作进行了优化,因为FP为我们带来了参考透明的优点 如何追踪来证明它 我认为计算出的值不会被重用 这类东西的一般问题是,x+y很便宜,但是您可以在那里进行一些操作,生成一个非常大的结果,您可能不想将其保存在内存中。这是一种冗长的说法,“这是一种时间/空间权衡” 因此,GHC似乎倾向于不重用工作,以防丢失的空间无法弥补获得的时间 确定答案的方法是让GHC在编

fxyz=[n | nx+y]
f 1 2[3,4]
x+y
是否一开始只执行一次,以便将连续调用替换为
值3
GHC
Haskell是否针对这项工作进行了优化,因为FP为我们带来了参考透明的优点

如何追踪来证明它

我认为计算出的值不会被重用

这类东西的一般问题是,
x+y
很便宜,但是您可以在那里进行一些操作,生成一个非常大的结果,您可能不想将其保存在内存中。这是一种冗长的说法,“这是一种时间/空间权衡”

因此,GHC似乎倾向于不重用工作,以防丢失的空间无法弥补获得的时间

确定答案的方法是让GHC在编译代码时转储Core。然后,您可以精确地看到将要执行的操作。(但要准备好让它变得非常冗长!)哦,还要确保打开优化!(即,
-O2
标志。)

如果您将您的功能重新表述为

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

f 1 2 [3,4]
fxyz=设s=x+y in[n | ns]
现在
s
肯定只执行一次。(即,每次调用
f
一次。每次调用
f
时,它仍将重新计算
s


顺便说一句,如果您对保存整个函数的已计算结果感兴趣,那么您要查找的搜索词是“记忆”。

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

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

f x y z = let s = x + y in [ n | n <- z, n > s ]
import Debug.Trace
f x y z=[n | n tx x+ty y]
其中tx=跟踪“x”
ty=轨迹“y”
main=打印$f 12[3,4]
通过7.8.3,我得到以下结果:

  • ghci:
    xyxy[4]
  • ghc(无优化):
    xyxy[4]
  • ghc-O2:
    xy[4]

  • 添加
    跟踪
    调用可能会影响CSE优化。但这确实表明-O2将提升
    x+y
    出循环。

    GHC可以进行类似的优化,您可以通过使用
    -O2
    -ddump siml
    编译来查看优化的内核。但这是一个棘手的问题。相反,最好为只希望计算一次的值指定一个名称。显式价值共享比隐式猜测更好。例如,
    f x y z=let value=x+y in[n | n值]
    。或者,您可以使用
    过滤器
    并获得相同的效果:
    过滤器(>x+y)z
    。。。在[n | nv]中是
    [n |让v=…,nv]
    。它们是等效的,所以请选择您喜欢的样式。感谢您提供的术语
    备忘录
    。是否因为技术挑战超过了感知到的性能提升,GHC在默认情况下不会像您提到的那样
    memonisation
    ?依我看,
    memonisation
    可以在某种程度上将应用程序从样板代码中解放出来,以重用价值,而且它看起来更具功能性而非强制性。
    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]