foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f acc [] = acc
foldr f acc (x : xs) = f x (foldr f acc xs)
ノートと呼ばれるこのような関数引数がf
に渡されました。 Haskellは遅延評価されているので、foldr
への再帰呼び出しは必ずしも実際には計算されません。f
は、第二引数を調べずに結果を返すことができます(ただしがx
には、それが2番目の引数を見たいかどうかをを決める最初の引数を調べることができる)場合は、foldr
コールは「早期に停止」することができ、なしリスト全体を調べる。ここで、(リストが空でない場合)foldl
再帰直ちに、それは再帰呼び出しに渡さアキュムレータ引数内部f
への呼び出しと
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f acc [] = acc
foldl f acc (x : xs) = foldl (f acc x) xs
。 f
は、再帰呼び出しを調べるかどうかを決定する機会を得ません。 foldl
は、再帰を維持する期間を完全に制御しており、リストの終わりを見つけるまで続行します。
特に、foldr
を使用すると、無限のリストを処理する可能性があります。最終的に渡す関数が第2引数(acc
)を参照しない限りGHCiの中にたとえば:
Prelude> foldr (\x acc -> if x > 10 then "..." else show x ++ ", " ++ acc) "STOP" [1..5]
"1, 2, 3, 4, 5, STOP"
Prelude> foldr (\x acc -> if x > 10 then "..." else show x ++ ", " ++ acc) "STOP" [1..]
"1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ..."
foldr
では、ラムダ関数は、である(リスト要素x
を調べ、リストの残りの部分を折るの結果を使用するかどうかを決定することif
ステートメントを使用することができますacc
によって参照されるが、実際にはまだ計算されていない)。
また、関数は再帰呼び出しを含む結果を返しますが、データコンストラクターのフィールドに格納することもできます。つまり、foldr
は無限にネストされたデータ構造を生成しますが、の呼び出し元のfoldr
は、無限の構造体のどれくらいを見たいかを決めることができるので、依然として呼び出し元がそれを処理できる有限の結果を返すことができます。例は次のようになります。
Prelude> take 10 $ foldr (\x acc -> x + 100 : acc) [] [1..]
[101,102,103,104,105,106,107,108,109,110]
ここで私はちょうどのみグラブを、map
と同じ仕事をするfoldr
を使用して順番に無限のリストを作成し、無限リストの各要素に100を追加したが、その後take 10
よ最初の10人。これは、リストの結果を折り畳む結果がリストコンストラクタ:
の2番目のフィールドに格納されているためです。
foldl
に渡す関数は、再帰の「どれくらい」を決定しないので、無限リストを処理する能力(実際に有限または無限の結果を返すかどうか)はfoldl
でシミュレートできません。使用する。 foldl
自体は、foldl
の別の呼び出し以外の何かを返す前に、リストの末尾まで繰り返されます。リストが無限であれば、foldl
への別の呼び出し以外の何かを返すことはありません。foldl
に渡す関数や、foldr
という仕事をするために使用するラッパーに関係なく、何も返しません。
無限のリストの処理だけではありません(それが難解だと思われる場合)。すべてのリストが有限であればはを使用してfoldr
と同じ結果を得ることができますが、リスト全体を調べるにはまだロックされていますが、実際に小さな接頭辞が必要な場合は非常に非効率です。
安全なバージョンの 'head'を考えてみましょう:' safeHead = foldr(\ x y - > Just x <|> y)Nothing'(そして 'Control.Applicative'をインポートしてください)。 'foldl'で定義された' foldr'のバージョンを使うと、 'safeHead [1. ..]'は終了しません。通常の 'foldr'では' Just1'をすぐに返します。 – Alec