`evaluate`、`rwhnf` 和 `seq` 与它们的“深层”对应物有什么区别?

Gui*_*rel 5 haskell lazy-evaluation

关于计时计算的 wiki 页面中,有一个为纯计算计时的示例。核心思想是使用函数evaluaternfseq确保1 + y在两次调用之间执行所需的计算(在下面的示例中)getCPUTime

time :: (Num t, NFData t) => t -> IO ()
time y = do
    start <- getCPUTime
    replicateM_ lim $ do
        x <- evaluate $ 1 + y
        rnf x `seq` return ()
    end   <- getCPUTime
Run Code Online (Sandbox Code Playgroud)

我想澄清一下函数的使用evaluaternfseq这里。

首先,将evaluate其参数评估为弱头范式,但它的另一个目的似乎是处理评估过程中可能发生的异常。我不确定没有它会发生什么,但我准备假设异常处理需要它。

然后,rnf将值计算为标准形式,以确保整个计算都发生在此处,并且由于调用evaluate. 正如这里所讨论的,这可能是也可能不是人们想要的,因为可能不需要额外的评估。

最后,seq确保rnf x在返回之前将表达式计算为弱头范式return ()

总结:evaluate处理潜在的异常,深入rnf评估x以确保整个计算是定时的,并seq确保及时rnf x评估。

以下是我的问题:

  1. 对已经将值评估为正常形式seq的调用的调用不是多余的rnf吗?
  2. 如果我更愿意将评估时间安排为弱头范式而不是范式,我可以简单地替换rnfrwhnf? 然后,将在3个电话evaluaterwhnf并且seq是多余的,这样我可以消除使用最后2和幸福只evaluate

Ale*_*nov 3

  1. 对 的调用seq并不多余,因为rnf x需要评估(到 WHNF)才能评估x到 NF,这就是seq的工作。

  2. 是的,我相信是这样:只是

    evaluate $ 1 + y
    return ()
    
    Run Code Online (Sandbox Code Playgroud)

但!如果这里的目的evaluate是处理异常,我认为它不起作用,因为它们rnf x也可以被抛出。如果不是,我看不出有什么好处

rnf (1 + y) `seq` return ()
Run Code Online (Sandbox Code Playgroud)

和 文档都force提出evaluate了一个更简单的替代方案:

evaluate $ force $ 1 + y
return ()
Run Code Online (Sandbox Code Playgroud)

也许该页面是在force可用之前编写的?即便如此,除非我错过了什么,

evaluate $ rnf $ 1 + y
Run Code Online (Sandbox Code Playgroud)

会正确完成这项工作。