什么是弱头范式(WHNF)是什么意思?什么是头标准型(HNF)和范式(NF)是什么意思?
熟悉的seq函数将表达式计算为我们称之为head normal form(缩写为HNF)的表达式.它一旦到达最外面的构造函数("头部")就会停止.这与正常形式(NF)不同,其中表达式被完全评估.
您还将听到Haskell程序员引用弱头正常形式(WHNF).对于正常数据,弱头正常形式与头部正常形式相同.差异只出现在功能上,而且我们在这里无关紧要.
我已经阅读了一些资源和定义(Haskell Wiki和Haskell邮件列表和自由词典),但我没有得到它.有人可能举一个例子或提供外行定义吗?
我猜它会类似于:
WHNF = thunk : thunk
HNF = 0 : thunk
NF = 0 : 1 : 2 : 3 : []
Run Code Online (Sandbox Code Playgroud)
如何做seq和($!)与WHNF和HNF有关?
我还是很困惑.我知道有些答案会忽略HNF.通过阅读各种定义,似乎WHNF和HNF中的常规数据之间没有区别.但是,它似乎与功能有所区别.如果没有差异,为什么还seq需要foldl'?
另一个混淆点来自Haskell Wiki,它指出seq减少到WHNF,并且对以下示例不做任何处理.然后他们说他们必须seq用来强迫评估.那不是强迫它到HNF吗?
常见的新手堆栈溢出代码:
Run Code Online (Sandbox Code Playgroud)myAverage = uncurry (/) . foldl' (\(acc, len) x -> (acc+x, len+1)) (0,0)了解seq和弱头正常形式(whnf)的人可以立即明白这里出了什么问题.(acc + x,len + 1)已经在whnf中,所以seq将值减少到whnf,对此无效.这段代码将像原始的foldl示例一样构建thunks,它们只是在元组内部.解决方案只是强制元组的组件,例如
Run Code Online (Sandbox Code Playgroud)myAverage …
我正在启动Haskell并且正在查看一些使用"!"定义数据类型的库.bytestring库中的示例:
data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
{-# UNPACK #-} !Int -- offset
{-# UNPACK #-} !Int -- length
Run Code Online (Sandbox Code Playgroud)
现在我看到这个问题是对这意味着什么的解释,我想这很容易理解.但我现在的问题是:使用它有什么意义?由于表达式将在需要时进行评估,为什么要强制进行早期评估?
在这个问题的第二个答案中,CV汉森说:"[...]有时懒惰的开销可能太多或浪费".这是否意味着它用于节省内存(保存值比保存表达式便宜)?
一个解释和一个例子将是伟大的!
谢谢!
[ 编辑 ]我想我应该选择一个没有{ - #UNPACK# - }的例子.所以让我自己做一个.这会有意义吗?是的,为什么以及在什么情况下?
data MyType = Const1 !Int
| Const2 !Double
| Const3 !SomeOtherDataTypeMaybeMoreComplex
Run Code Online (Sandbox Code Playgroud)