因此,Haskellseq
函数强制评估它的第一个参数并返回第二个参数。因此它是一个中缀运算符。如果你想强制评估一个表达式,直觉上这样的特性将是一个一元运算符。所以,而不是
seq :: a -> b -> b
这将是
seq :: a -> a
因此,如果您想要的值是a
,为什么要返回b
以及如何构造b
. 显然,我不是在考虑 Haskell。:)
因此,Haskellseq
函数强制评估它的第一个参数并返回第二个参数。因此它是一个中缀运算符。如果你想强制评估一个表达式,直觉上这样的特性将是一个一元运算符。所以,而不是
seq :: a -> b -> b
这将是
seq :: a -> a
因此,如果您想要的值是a
,为什么要返回b
以及如何构造b
. 显然,我不是在考虑 Haskell。:)
思考的方式a `seq` b
不是它“评估”,而是它在anda
之间创建依赖关系,因此当您进行评估时,您也会进行评估。a
b
b
a
这意味着,例如,这a `seq` a
完全是多余的:你告诉 Haskell 在评估a
时进行评估a
。按照同样的逻辑,seq a
只有一个论据与简单地自己编写没有什么不同a
。
只是seq a
以某种方式评估a
是行不通的。问题是它seq a
本身就是一个可能不会被计算的表达式——例如,它可能在一些嵌套的 thunk 内部。因此,只有当您开始评估整个表达式时,它才会变得相关seq a
——此时您a
无论如何都会自己评估。
@Rhymoid 关于如何在严格折叠 ( foldl'
) 中使用它的示例很好。我们的目标是编写一个折叠,以便acc
在我们评估最终结果后,在每一步都完全评估其中间累加值 ( )。这是通过seq
在累积值和递归调用之间添加 a 来完成的:
foldl' f z (x:xs) =
let z' = f z x in z' `seq` foldl' f z' xs
seq
您可以将其可视化为折叠中每个应用程序之间的长链f
,将所有应用程序连接到最终结果。这样,当您评估最终表达式(即通过对列表求和得到的数字)时,它会严格评估中间值(即当您折叠列表时的部分总和)。