当参数出现多次时,在Haskell中进行惰性求值的性能

DB *_*sai 8 haskell lazy-evaluation

假设我有一个函数可以计算由四个定义的数字的幂

let power4 x = x*x*x*x
Run Code Online (Sandbox Code Playgroud)

我尝试传递x =(3 + 8)*2

let result = power4 ((3 + 8)*2) 
Run Code Online (Sandbox Code Playgroud)

因为在Haskell中,值被评估直到需要它们,这是否意味着x将评估四次?如果是这样,有没有办法改进Has​​kell编译器?

谢谢.

luq*_*qui 10

不,它只会被评估一次.在按名称调用时,它将被评估四次,但所有Haskell实现都是按需调用的(尽管标准不需要这样),这意味着每个表达式最多只会被评估一次.

这仅适用于表达式完全具体的情况.例如,无法保证:

foo x = x + (1+2)

bar = foo 3 + foo 4
Run Code Online (Sandbox Code Playgroud)

计算时bar,(1+2)只会评估一次.事实上,它可能会被评估两次(如果没有优化编译).


ken*_*ytm 9

如果你不确定,你可以trace用来检查(参考:http://www.haskell.org/haskellwiki/Debugging):

import Debug.Trace

power4 x = x*x*x*x

main = print $ power4 (trace "called" ((3+8)*2))
Run Code Online (Sandbox Code Playgroud)

结果:

called
234256
Run Code Online (Sandbox Code Playgroud)

所以表达式只评估一次.

  • 我也倾向于使用该技巧检查实现行为.例如,`power4 x =(trace"称为"x)*(跟踪"称为"x)*(跟踪"称为"x")*(跟踪"称为"x)"将输出""调用"`优化,否则四次.在这种情况下,我认为这正确地说明了实际发生的事情(我认为这是CSE踢的但是GHC没有为这种结构执行CSE,必须是其他的东西).不过,我想知道`trace`是否使用`unsafePerformIO`,它总是一个正确的一般检查程序. (2认同)