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

sof*_*sof 0 haskell lazy-evaluation

它表明ghci下面是懒惰的,

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

1
1
2
Run Code Online (Sandbox Code Playgroud)

编译后运行下面的代码显示默认值ghc严格性分析器增强.

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

1
2
Run Code Online (Sandbox Code Playgroud)

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

lef*_*out 7

这与严格无关.如果你想一想,GHCi的行为实际上是愚蠢的:它"计算" x两次.懒惰与否,常数不应该被计算两次!

发生了什么:x有一个通用数字类型Num a => a.这意味着,它的实现并不仅仅是一个常量,而是一个带有"类型"的函数 - (实际上是一个字典 - )参数.功能一般不memoise可行的,所以这样的多态值当你需要它的价值重新计算.这很烦人,因此标准的Haskell通过一种有争议的措施避免了这一点,即单态性限制.它基本上消除了多态性,如果它可以因此将值转换为恒定的应用形式.因此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
Run Code Online (Sandbox Code Playgroud)

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