2012-06-15 32 views
36

我一直在想这个很多,但我一直没能找到任何有关它。seq功能和严格

当使用seq功能,是怎么做的,然后真的工作?在任何地方,只是解释说seq a b评估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) 

我发现它有点难以获得关于此功能的功能的细节。

+7

这可能是有帮助的:http://stackoverflow.com/questions/6872898/haskell-what-is-weak-head-normal-form“它的语义是seq xy意味着每当y被评估为弱头正常形式,x也被评估为弱头正常形式。“ – shang

回答

29

你并不孤单。 seq可能是最难的Haskell函数之一,因为几个不同的原因可以正确使用。在你的第一个例子:评估bar q t之前

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

q进行评估。如果bar q t从未评估,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从来没有评估过,第一个也不需要。所以seq x x完全等同于x

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

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

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

xs必须是一个列表,因为map。当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。

编辑:(感谢丹尼尔·瓦格纳在意见建议)

对于函数,seq将计算表达式,直到功能“有一个拉姆达的表现”,这意味着它已经准备好应用。下面是一些例子,可能表明这意味着什么:

-- 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与函数有关的一些后果略有介绍。

+3

只是要说清楚:关于_when_'seq'应该是没有任何功能的争论。当函数“具有lambda显示”时,它是无操作的,而当某个计算必须在lambda达到最顶点之前完成(因此可用于应用程序)时,不是无操作。争议是关于在设计优化时我们是否应该考虑使用'seq' - 因为'seq'在Haskell的语义中占据了一个不舒服的空间。 –

+0

@DanielWagner - 这是一个很好的观点。我想不出有什么好的解释方法(当然不如你),所以相反,我指出wiki希望读者可以从那里的例子中推断出它,这只是在你指出的时候有点相关。我将在编辑中添加更多内容。 –

+0

你的回答表明,'''''seq a b''''首先评估''''a'''',但是这篇文章不一定是真的。因此''''pseq''''存在。 https://wiki.haskell.org/Seq“然而,评估b然后a,然后返回b是一件完全合理的事情;这是为了防止pseq被发明的这种模糊性,但那是另一个故事“。 –

4

你能想到的seq为:

seq a b = case a of 
      _ -> b 

这将评估a硬碰硬范式(WHNF),然后继续评估b

编辑评论后奥古斯塔评论:case ... ofstrict, GHC Core one,它始终强制其论点。

+1

除了Haskell不评估'a'。 – augustss