理解`runEval` - 不是WHNF?

时间:2016-07-09 17:56:46

标签: haskell

假设:

Prelude> import Control.Parallel.Strategies 
Prelude> import Control.Parallel
Prelude> let fact n = if (n <= 0) then 1 else n * fact (n-1) :: Integer
Prelude> let xs = map (runEval . (\x -> return x :: Eval Integer) . fact) [1..100]
Prelude> let ys = map fact [1..100]
Prelude> :sprint xs
xs = _
Prelude> :sprint ys
ys = _

据我了解,xs处于弱头范式。这是为什么? runEval是否对将值/计算带到普通表单有任何影响?

1 个答案:

答案 0 :(得分:2)

原因是let只是将一个名字与一个表达式绑定,但它不会触发对表达式的任何评估。

为了更好地理解,让我使用一个更简单的例子

Main> let x = error "foobar!" in 1
1

正如您所看到的,应该抛出应该抛出异常的error "foobar!"。原因是没有使用x,因此Haskell没有对其进行评估。您需要触发评估x

的内容
Main> let x = error "foobar!" in x `seq` 1
*** Exception: foobar!

回到您的示例,请注意Eval x指定如何评估x,而不是在程序中评估它的时间。

请查看Lazyness上的这篇wiki文章了解更多信息。