是否可以在GHC上关闭严格性分析仪?

时间:2016-12-01 20:29:33

标签: haskell lazy-evaluation

它显示ghci在下面全部是懒惰的,

ghci > let x = trace "1" 1 in x + x

1
1
2

编译后运行以下代码,strictness analyzer增强了默认ghc

main = do print $ let x = trace "1" 1 in x + x

1
2

但即使将-O0 -fno-strictness选项传递给ghc,为什么结果仍然相同?

1 个答案:

答案 0 :(得分:7)

这与严格性无关。如果你考虑一下,GHCi的行为实际上是愚蠢的:它“计算”x两次。懒惰与否,常数不应该被计算两次!

发生了什么:x的通用数字类型为Num a => a。这意味着,它的实现并不仅仅是一个常量,而是一个带有“类型”的函数 - (实际上是一个字典 - )参数。函数通常不可能进行记忆,因此只要需要其值,就会重新计算这样的多态值 。这很烦人,因此标准Haskell通过一个有争议的措施monomorphism restriction来避免这种情况。它基本上消除了多态性,如果它可以因此将值转换为constant applicative forms。因此,使用更简单的类型x来推断Integer,其中然后是一个常量,它只在计算一次时触发trace而第二次评估只是重新计算使用已知的值。 (这是“适当的懒惰”行为!)

你在GHCi中没有看到这个的原因是从版本7.8开始,它默认关闭了单态限制!您可以将其打开以查看其功能:

GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
Prelude> :m +Debug.Trace
Prelude Debug.Trace> let x = trace "1" 1 in x + x
1
1
2
Prelude Debug.Trace> :set -XMonomorphismRestriction 
Prelude Debug.Trace> let x = trace "1" 1 in x + x
1
2

幸运的是,在实际程序中,即使将单态性限制设置为 off ,也不会发生双重评估,因为当在函数体中定义x时,编译器可以看到在函数的范围内,它不是多态的。因此,您的第二个代码永远不应该跟踪1两次。 (尽管总是记住,trace只是一个粗略的调试工具,它真的可以对付语言的粒度 - 通常不会指望它有任何可重现的行为。)