結合機能が第2引数で遅延している場合、右折はすぐに生成を開始できます。単純な例:
foldr1 (++) ["one", "two", "three", ...]
~> "one" ++ foldr1 (++) ["two", "three", ...]
、結果の最初の部分は、さらに(++)
の第2引数を評価せずにすぐにアクセス可能です。これは、最初の部分が消費されたときにのみ評価する必要があります。多くの場合、最初の部分はすでにガベージコレクションされています。
結合関数としてf = flip const
の例では、2番目の引数に厳密な(1)の厳密な条件がありますが、全く評価する必要はありません。それは最初のものを無視します。それは右の折り畳みにも適しています。ここでは、
foldr1 f [x1, x2, x3, ... ]
~> f x1 (foldr1 f [x2, x3, ... ])
を行くと、今最も外側f
はすぐ
~> foldr1 f [x2, x3, ... ]
~> f x2 (foldr1 f [x3, ... ])
~> foldr1 f [x3, ... ]
と各ステップで評価することができ、最も外側のf
は常にすぐに(完全に)評価することができ、かつ1つのリスト要素は捨て。
リストは順次消費時に一定の間隔でそれを作成することができる発電機により与えられた場合、
last = foldr1 (flip const)
は、一定の間隔で実行することができます。
左の折り目では、物が異なります。それはテール再帰的なので、
foldl1 f (x:y:zs) = foldl f x (y:zs) = foldl f (f x y) zs
リストが終わるまで何も返すことができません。特に、左折は決して無限のリストで終了することはできません。
は今、私たちの場合f = flip const
を見て、我々はすぐにx2
にf x1 x2
を評価することが可能となり、その後、f x2 x3 = x3
が、それは、この特別なf
のためにのみ可能であるだろう。もちろん、
foldl1 f [x1, x2, x3, x4, ...]
~> foldl f x1 [x2, x3, x4, ... ]
~> foldl f (f x1 x2) [x3, x4, ... ]
~> foldl f (f (f x1 x2) x3) [x4, ... ]
を見つけます。
foldl
は一般的な高次関数なので、中間結果が決して必要とされない可能性があるため、中間結果を評価することはできません。実際にはここでは必要ありません。リストは、1式
f (f (f (f ...y3) y2) y1) y0
~> y0
を取得し、最も外側のf
は、最初の引数を構築するネストされたf
秒の巨大なサンクを見ずに評価することができます。
foldl
(foldl1
)は、中間結果を直ちに評価する方がはるかに効率的であることがわかりません。
厳密左折り目、foldl'
とfoldl1'
は、それらが(最も外側の値コンストラクタまたはラムダに)弱いヘッド正規形に中間結果を評価し、
last = foldl1' (flip const)
も非常に効率的であることを行います。
しかし、中間結果がfoldr
よりもさらに評価されているので、彼らは少し少なめに効率的である、と、任意のリスト要素が⊥
であれば重要なのは、foldl1'
バージョンは⊥
を返します:
foldl1' f [x1, ⊥, x3, x4]
~> foldl' f x1 [⊥, x3, x4]
~> case f x1 ⊥ of
pattern -- that causes ⊥
~> ⊥
foldr1
のバージョンでは、リスト要素や中間結果をまったく検査しないため、問題はありません。
(1)f
すなわち、2番目の引数に厳密では、単純に2番目の引数を返す
f x ⊥ = ⊥
f
ので、それは明らかにそうであることを意味します。
foldlは怠惰ですが、foldrは厳密です。試してみてください$ fold1 'http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-List.html#v:foldl1-39- – DiegoNolan
@DiegoNolan 'foldr'は厳密ではありません。それはあなたが怠惰を測定する方法によって 'foldl'よりもずっと怠惰です。 – sepp2k
'(flip const)x y'はちょうど' y'です。蓄積するものはありません。 –