2011-12-09 10 views
7

foldrのように、リスト内包と融合しているようです。したがって、この例ではfoldl(21mb)と比較してメモリが少なくて済みます。リスト内包表記に中間データ構造が作成されています

myfunc = sum $ foldr g acc [ f x | x <- xs ] 
f x = .. 
g x y = .. 

誰でもどのように、なぜそれを説明できますか?また、どのように怠惰な評価がこれに役立ちます。

答えて

8

リスト全体を横断する前に、左折で出力(結果の一部)を生成することはできません。折りたたむ機能に応じて、大量のデータ構造や大量のメモリを使用することがあります。メモリを大量に使用します(たとえば、Intのリストに(+)を付けると定数メモリで実行できます)。

適切な機能(第2引数を検査せずに[部分]結果を生成できる)の場合、結果を適切に消費し、入力リストが適切に生成されると、全体の計算は小さな一定の空間で実行できます。 sclvが言ったように、それは基本的にこれらの場合のループに減少します。

+0

私はfoldrとfoldlをはっきりと区別しているので、この答えを選びます。 – vis

8

本質的には、map f xsのように理解することはできません。これをコンパイルしている場合、ghcは合計、倍数、マップを単一のパス(http://www.haskell.org/haskellwiki/Correctness_of_short_cut_fusion)に融合する必要があります。しかし、あなたがいなくても、怠け者はあなたの友人です。マップによって生成されたリストは、lazy-fが要求されたときにのみ適用されます。そして、fは折り畳み者がそれを要求するときにのみ要求される。あなたの折り畳み者が明らかに別の(怠惰な)リストを作成しているので、折り畳みの各ステップは順番に合計によって要求されます。したがって、各関数は順番に適用されますが、すべての中間データ構造を一度に生成する必要はありません。関数合成の全面的なセットを書いているが、評価モデルはこの特定のコードセットを扱う傾向があり、手を振って、ループのように(ただし、融合しないで、かなりの量のループインダイレクション)。

+3

私はdownvoteの理由を知りたいです。 –

+1

リンクに感謝します。それは有用だった。 – vis

1

これはGHCコンパイラの機能です。基本的に、GHCは、リストが「パイプライン」でいつ使用されるかを認識し、リスト全体を割り当てないCのwhile -loopに相当するものにコンストラクト全体を変換することができます。

foldrで動作し、foldlではない理由は、使用している関数gによって異なります。 foldrので、foldlとは反対に、結果パラメータとして与えられた関数のを蓄積(通称:それは未評価の機能の巨大な「サンク」を構築して、それは、機能gを評価し、実際に始めることができる前に、リスト全体を必要とfoldlリストの最後の要素がその結果として得られます。これは、この場合には非常に多くのメモリを使用する理由です.はリスト入力を取得するとすぐにgの評価を開始できます)、アキュムレータでは「strict」と呼ばれ、最適化につながる可能性のある特定の前提がコンパイラによって作成される可能性があります。

例えば、機能gがリストされた値が得られ、場合、それが消費を一覧表示するリストの作成から、(基本的にmapようfoldrを処理し、全体の構造を作り、前述の「パイプライン」の最適化戦略を継続することができます)を厳密なループに変換します。これは、foldrが、消費するすべてのリスト要素に対して正確に1つのリスト要素を生成するためです(foldlは特に無限リストの場合)。

+2

これはGHCの特徴ではありません。 GHCは、リストだけでなく、あらゆるライブラリの書き換えルールをサポートしています。折り畳み/折りたたみ融合はそれに基づいています。ありがとう。 –

関連する問題