为什么预定义的`const`函数在某些情况下的行为与等效的lambda函数不同?

问题描述 投票:3回答:1

[进行共享实验时,我发现预定义的const函数在某些情况下的行为有所不同。

f :: (() -> Int) -> Int
f g = g () + g ()

x1 = f (const   (trace "x1" 42))
x2 = f (\_ ->   (trace "x2" 42))
x3 = f (myconst (trace "x3" 42))

myconst :: a -> b -> a
myconst x _ =  x

this example的编译没有优化时,评估x1仅触发一次trace评估,而针对x2x3评估两次。由于lambda函数,这对于x2是合理的。

x1
x2
x2
x3
x3
252

definitionconst暗示,这是一个普通的函数定义,没有任何编译器注释可以解释差异。因此,函数myconst的行为应与否相同。如何解释这种行为,并在这方面有办法影响编译器?

haskell lambda sharing
1个回答
0
投票

如果myconst被编译成一个单独的模块(即使该单独的模块是用-O0编译的,则输出为:

x1
x2
x2
x3
252

不同之处在于,在-O0代码中,在单独的模块中调用myconst会生成代码:

let x' = myconst (trace "x3" 42) in x' + x'

但是在同一模块中调用myconst内联如下:

trace "x4" 42 + trace "x4" 42

-O2编译会完全更改代码-内联所有内容,并且将跟踪移到表达式的顶部,因此它们仅执行一次。

您可以在这方面明显地影响编译器,例如,可以通过将myconst放在或不放在单独的模块中,或者-如@leftroundabout所指出的那样-通过添加各种内联编译指示。

我认为您不能可靠地在这方面影响编译器,而且我不确定您可以通过研究未优化的编译输出了解多少有关实际GHC代码的知识。我认为以上示例清楚地表明,基于-O0生成的代码将基于完全不需要的编译方面,以完全任意和自相矛盾的方式运行。

© www.soinside.com 2019 - 2024. All rights reserved.