【发布时间】:2014-07-15 10:20:13
【问题描述】:
我一直在玩 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。我的问题是:
为什么在执行let z = (x,x) 时,REPL 中的z 被评估为 WHNF,但在从文件加载定义时却没有。我的怀疑是
它与模式绑定有关,但我不知道在哪里查找以进行澄清(也许我完全错了)。我本来希望它以某种方式表现得像文件中的示例。
任何提示或简要解释为什么会发生这种情况?
【问题讨论】:
-
因为
(,)是一个构造函数,所以区别对 Haskell 的语义没有影响(:sprint提供对内部 thunk 实现细节的访问,所以不计算在内。)所以这是一个优化的问题以及 GHC 在不同位置编译(x,x)时所做的权衡。其他人可能知道这些情况的确切原因。 -
@ØrjanJohansen 我觉得你的评论应该是一个答案。
-
@Codygman 如果你这么认为。不过,我真的不太了解它,所以我一直希望“其他人”能出现。
标签: haskell lazy-evaluation ghci thunk weak-head-normal-form