seq功能和严格性

我一直在想这很多,但我一直没有找到任何关于它的事情。

当使用seq功能时,它如何真正起作用? 在任何地方,只是解释说seq ab评估a ,丢弃结果并返回b

但是,这到底意味着什么? 以下将导致严格的评估:

foo s t = seq q (bar q t) where
      q = s*t

我的意思是,在q严格在使用前评估bar ? 以下是否等同:

foo s t = seq (s*t) (bar (s*t) t)

我觉得有点难以弄清这个功能的功能。


你不是一个人。 由于几个不同的原因, seq可能是最难以使用的Haskell函数之一。 在你的第一个例子中:

foo s t = seq q (bar q t) where
      q = s*t

q在评估bar qt之前评估。 如果bar qt永远不会被评估, q也不会。 所以,如果你有

main = do
    let val = foo 10 20
    return ()

因为val从不使用,所以不会被评估。 所以q也不会被评估。 如果你有

main = print (foo 10 20)

foo 10 20的结果进行评估(通过print ),因此在fooqbar的结果之前进行评估。

这也是为什么这不起作用:

myseq x = seq x x

在语义上,这意味着第一个x将在评估第二个x之前被评估。 但是如果第二个x从来没有被评估过,那么第一个x也不需要。 所以seq xxx完全等价。

你的第二个例子可能是也可能不是一回事。 在这里,表达式s*t将在bar的输出之前被评估,但它可能与s*t一个bar参数的s*t 。 如果编译器执行常见的子表达式消除,它可能会共同使用两个相同的表达式。 尽管GHC在CSE的哪个位置可以保持相当保守,所以你不能依赖这个。 如果我定义bar qt = q*t它会在bar中使用该值之前执行CSE并评估s*t 。 对于更复杂的表达式可能不这样做。

您可能也想知道严格评估意味着什么。 seq将第一个参数评估为弱头标准形式(WHNF),对于数据类型来说,这意味着解包最外层的构造函数。 考虑这个:

baz xs y = seq xs (map (*y) xs)

由于map原因, xs必须是一个列表。 当seq评估它时,它本质上将代码转换为

case xs of
  [] -> map (*y) xs
  (_:_) -> map (*y) xs

这意味着它将确定列表是否为空,然后返回第二个参数。 请注意,没有评估任何列表值。 所以你可以这样做:

Prelude> seq [undefined] 4
4

但不是这样

Prelude> seq undefined 5
*** Exception: Prelude.undefined

无论您使用什么样的数据类型作为seq第一个参数,对WHNF的评估将足够远以找出构造函数,而不再进一步。 除非数据类型的组件使用爆炸模式标记为严格。 然后所有严格的领域也将被评估为WHNF。

编辑:(感谢Daniel Wagner在评论中的建议)

对于函数, seq将评估表达式,直到函数“具有lambda显示”,这意味着它已准备好应用程序。 以下是一些可能证明这意味着什么的例子:

-- ok, lambda is outermost
Prelude> seq (x -> undefined) 'a'
'a'

-- not ok.  Because of the inner seq, `undefined` must be evaluated before
-- the lambda is showing
Prelude> seq (seq undefined (x -> x)) 'b'
*** Exception: Prelude.undefined

如果你认为lambda绑定是一个(内置的)数据构造函数, seq函数与在数据上使用它完全一致。

此外,“lambda绑定”包含所有类型的函数定义,无论是由lambda表示法定义还是作为普通函数定义。

HaskellWiki seq页面的Controversy部分对seq在功能方面的一些后果略有介绍。


你可以把seq想成是:

seq a b = case a of
            _ -> b

这将评估a头正常形式(WHNF),然后继续评估b

在8月份的评论之后进行编辑:这种case ... of是严格的,GHC Core版本,它总是强制它的论点。

链接地址: http://www.djcxy.com/p/42967.html

上一篇: the seq function and strictness

下一篇: Advantages of strict fields in data types