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

问题描述 投票:0回答:1

我一直在学习严格与惰性的数据结构,并且一直在使用

:sprint
命令 高铁。我对
: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 = _

我的问题是:为什么

a
默认评估为WHNF,但
b
仍然是一个thunk?

我期待

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

ghci> seq a ()
()
ghci> seq b ()
()
ghci> :sprint a
a = <Foo> _ _
ghci> :sprint b
b = <Bar> 5 _
haskell lazy-evaluation
1个回答
1
投票

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

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
的应用的引用,而不是直接对构造函数
Bar
的应用。
seq
只是一个函数;它在实现方面很特别,但在内存中以构造函数的方式进行特殊表示方面并不特殊。对(非构造函数)函数应用程序的引用只是一个 thunk,因此 GHCi 将其显示为任何其他 thunk:
b = _
.

Forcing

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

© www.soinside.com 2019 - 2024. All rights reserved.