为什么具有严格字段的​​数据结构不能立即评估为 WHNF?

sim*_*ver 3 haskell lazy-evaluation

我一直在学习严格数据结构与惰性数据结构,并且一直在使用:sprintghci 中的命令。我的理解:sprint是它显示所选变量的评估状态。我遇到了以下我无法理解的好奇心。

ghci> data Foo = Foo{i::Int,j::String}
ghci> data Bar = Bar{i:: !Int, j::String}
ghci> 
ghci> 
ghci> a = Foo (3+2) "abc"
ghci> b = Bar (3+2) "abc"
ghci> 
ghci> :sprint a
a = <Foo> _ _
ghci> :sprint b
b = _
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么a默认情况下评估为 WHNF,但b仍然是 thunk?

我期望的输出bb = <Bar> 5 _,我可以通过运行来强制输出seq b ()

ghci> seq a ()
()
ghci> seq b ()
()
ghci> :sprint a
a = <Foo> _ _
ghci> :sprint b
b = <Bar> 5 _
Run Code Online (Sandbox Code Playgroud)

Ben*_*Ben 7

我相信这是因为严格字段只是语法糖,告诉编译器自动seq在某些地方插入调用。

因此,严格注释意味着Bar实际上b = Bar (3+2) "abc"被编译为类似b = let x = 3+2 in seq x (Bar x "abc").

之后a = Foo (3+2) "abc"a是对构造函数的应用程序的引用Foo;它的字段包含 thunk。构造函数被特殊对待,因此 GHCi:sprint可以知道a引用构造函数应用程序并将其显示为a = <Foo> _ _

但之后b = Bar (3+2) "abc"b是对应用程序的引用seq,而不是直接对应用程序的构造函数的引用Barseq只是一个函数;它的特殊之处在于其实现,但并不像构造函数那样在内存中专门表示。对(非构造函数)函数应用程序的引用只是一个 thunk,因此 GHCi 将其显示为任何其他 thunk:b = _

强制by 引用的 thunkb会强制3 + 2然后导致对构造函数的应用程序的引用Bar。但是绑定变量不会自动强制分配给它的表达式。