6

<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
4

3 に答える 3

13

あまり知られていませんが、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' が厳密である」ということは、「アキュムレータの引数が厳密である」ことを意味すると素朴に考えたでしょう。上記はそれに反する。

ただし、厳密さはループのコンスケースでの関数適用の結果にのみ適用されるため、さらに陰湿です。したがって、基本ケースに入ると底が得られますが、帰納的ケースは得られません。

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

したがって、引数 2の厳密性 も引数 3 のに依存します!

これは私がそれをどのように書くかです: 2 番目の引数で「完全に」厳密です。

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

ご覧のとおり、これは 2 番目の引数で本当に厳密です。

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 の博士論文に記載されています。

于 2013-01-11T16:39:17.557 に答える
7

foldl と (厳密な) foldl' は意味的にほぼ同等です。違いは、特に大きなリストを横断する場合のパフォーマンスにあります。怠惰にはサンクを構築するオーバーヘッドがあり、foldl' は巨大なサンクを構築しないため、その結果に到達するためのより効率的な方法です。

Haskell Wikiには、これについて詳しく説明している非常に優れた記事があります。

厳密な関数は、引数が一般に積極的に評価されるという点で、C やその他の言語の関数のように機能します。

于 2013-01-11T13:54:56.263 に答える
1

正格関数は、本体が評価される前に引数が評価される関数です。

于 2013-01-11T13:30:13.493 に答える