【问题标题】:How is Haskell's seq used?Haskell 的 seq 是如何使用的?
【发布时间】:2017-01-31 09:27:26
【问题描述】:

因此,Haskell seq 函数强制评估它的第一个参数并返回第二个参数。因此它是一个中缀运算符。如果你想强制评估一个表达式,直觉上这样的特性将是一个一元运算符。所以,而不是

seq :: a -> b -> b

应该是

seq :: a -> a

因此,如果你想要的值是a,为什么要返回b,你如何构造返回b。显然,我不是在考虑 Haskell。 :)

【问题讨论】:

标签: haskell strictness


【解决方案1】:

考虑a `seq` b 的方式不是它“评估a”,而是它在ab 之间创建依赖关系,因此当您评估b 时,您评估@987654326 @也一样。

这意味着,例如,a `seq` a 是完全多余的:当您评估 a 时,您是在告诉 Haskell 评估 a。按照同样的逻辑,seq a 仅带有一个参数与简单地编写 a 本身并没有什么不同。

仅仅让seq a 以某种方式评估a 是行不通的。问题是seq a 本身就是一个可能不会被计算的表达式——例如,它可能在一些嵌套的thunk 内部。因此,只有在您评估整个 seq a 表达式时,它才会变得相关 - 无论如何,此时您将一直在评估 a

@Rhymoid 关于如何在严格折叠中使用它的示例 (foldl') 很好。我们的目标是编写一个折叠,以便在我们评估最终结果后,在每一步都完全评估其中间累加值 (acc)。这是通过在累积值和递归调用之间添加seq 来完成的:

foldl' f z (x:xs) = 
  let z' = f z x in z' `seq` foldl' f z' xs

您可以将其可视化为折叠中f 的每个应用程序之间的seq 长链,将所有应用程序连接到最终结果。这样,当您评估最终表达式(即通过对列表求和得到的数字)时,它会严格评估中间值(即当您折叠列表时的部分总和)。

【讨论】:

  • 我现在认为seq 创建的依赖是多余的,至少在上述foldl 的情况下,因为常规foldl 已经对z' 施加了这样的依赖约束使用它的优点......似乎。
  • @George foldl (\x y -> 1) undefined [2] 评估为 1,而不是尝试评估 undefined。相比之下,使用foldl' 会出错,因为它确实会评估它。
  • @George 您在其他语言中习惯的不适用于 Haskell 的特征之一是:函数应用程序显然不会“使用”应用程序中的所有参数。特别是,仅仅因为应用程序foldl' f z' xs 具有z' 作为参数并不必然(即不检查foldl' 的定义)意味着z' 被使用。这就是您关于使用 z' 的论点失败的地方:z' 是函数的参数,因此不一定使用。
猜你喜欢
  • 1970-01-01
  • 2019-07-21
  • 1970-01-01
  • 1970-01-01
  • 2016-01-08
  • 2011-09-20
  • 2017-09-11
  • 2017-11-27
  • 1970-01-01
相关资源
最近更新 更多