haskell中严格版本的含义是什么?

时间:2013-01-11 13:28:16

标签: lazy-evaluation haskell strictness

关注< Real World Haskell> ,据说foldl'foldl的严格版本。

但我很难理解,strict意味着什么?

foldl f z0 xs0 = lgo z0 xs0
         where
            lgo z []     =  z
            lgo z (x:xs) = lgo (f z x) xs


foldl' f z0 xs0 = lgo z0 xs0
    where lgo z []     = z
          lgo z (x:xs) = let z' = f z x in z' `seq` lgo z' xs

3 个答案:

答案 0 :(得分:12)

它并不广为人知,但foldl'在累加器参数中实际上是非严格的!回想一下类型:

foldl' :: (a -> b -> a) -> a -> [b] -> a

它在参数2中的严格程度取决于为参数1给出的函数的严格性,因为你看是否通过了const

Prelude Data.List> foldl' (const (+1)) undefined [1]
2
Prelude Data.List> foldl' (const (+1)) undefined [1..4]
5

你会天真地想,“foldl'是严格的”意味着“累加器参数中的严格”。上述内容与此相矛盾。

然而,它更加阴险,因为严格性仅仅是在循环的cons情况下函数应用的结果。如果你输入基础案例,你仍然会得到底部,但不是诱导案例:

Prelude Data.List> foldl' (const (+1)) undefined []
*** Exception: Prelude.undefined

严格性in argument 2 取决于参数3的

这就是我写它的方式:第二个论点中的“完全”严格。

foldl' f z0 xs0 = go z0 xs0
  where
    go !z []     = z
    go !z (x:xs) = go (f z x) xs

在第二个论点中,这是真正严格的,你可以看到:

Prelude Data.List.Stream> foldl' (\a b -> 1) undefined [undefined]
*** Exception: Prelude.undefined

与Haskell2010版本相比:

Prelude Data.List.Stream> Data.List.foldl' (\a b -> 1 ) undefined [undefined]
1

此实际具有实际影响 - 当前定义不会一致地取消其累加器参数。

历史记录:当我们在2007年为流融合论文指定列表库的严格语义时发现了这一点,并且在Duncan Coutt的PhD thesis中给出了指定严格性的方法。

答案 1 :(得分:6)

foldl和(严格)foldl'接近于语义上的等价物。不同之处在于性能,尤其是在横切大型列表时。懒惰有建立一个thunk和foldl'的开销是更有效的方式来达到这个结果,因为它不会构建一个巨大的thunk。

有一篇非常好的文章详细解释了Haskell Wiki

严格的函数就像C语言或其他语言中的函数一样,因为它们的参数通常都是热切评估的。

答案 2 :(得分:0)

严格函数是一个函数,其参数在正文之前进行求值。