42

我一直在玩 Simon Marlow 关于 Haskell 中并行和并发编程的书中的一些示例,并偶然发现了一个我不太了解的有趣行为。这真的是关于我试图了解 GHC 的一些内部工作原理。

假设我在 REPL 中执行以下操作:

λ» let x = 1 + 2 :: Int
λ» let z = (x,x)
λ» :sprint x
x = _
λ» :sprint z
z = (_,_)
λ» seq x ()
()
λ» :sprint z
z = (3,3)

好的,这几乎是我所期望的,只是 z 已经被评估为 WHNF。让我们编写一个类似的程序并将其放在一个文件中:

module Thunk where

import Debug.Trace

x :: Int
x = trace "add" $ 1 + 2

z :: (Int,Int)
z = (x,x)

并在 GHCi 中摆弄它:

λ» :sprint x
x = _
λ» :sprint z
z = _
λ» seq x ()
add
()
λ» :sprint z
z = _
λ» seq z ()
()
λ» z
(3,3)

所以这有点不同:z没有提前评估为 WHNF。我的问题是:

为什么z在执行时会在 REPL 中评估为 WHNF,let z = (x,x)但在从文件加载定义时不会。我怀疑它与模式绑定有关,但我不知道在哪里查找以进行澄清(也许我完全错了)。我本来希望它以某种方式表现得像文件中的示例。

任何指示或简要解释为什么会发生这种情况?

4

1 回答 1

2

因为(,)是构造函数,所以区别对 Haskell 的语义没有影响(允许访问内部 thunk 实现细节,所以不计算在内。)所以这是一个问题,即 GHC在不同位置:sprint编译时做了哪些优化和权衡。(x,x)在这些情况下,其他人可能知道确切的原因。

于 2015-03-03T07:18:51.650 回答