これをやろう。
•レイジーシーケンスは、要求されたシーケンス内のアイテムのみを評価することを知っていますが、これはどのように行われますか?
レイジーシーケンス(以降、私はLPであるため、LS、またはレイジーパーソン)はパーツで構成されます。評価されたシーケンスのヘッド、または部分(実際には32個の要素が一度に評価されます。Clojure1.1の時点で、1.2と思います)の後には、基本的にチャンクであるサンクと呼ばれるものが続きます。呼び出されるのを待っている情報(シーケンスを作成する関数の残りの部分、未評価と考えてください)。呼び出されると、サンクは要求された量を評価し、必要に応じてコンテキストを使用して新しいサンクが作成されます(すでに呼び出されている量なので、以前の場所から再開できます)。
つまり、あなたは–整数の怠惰なシーケンスである(take 10 (whole-numbers))と仮定します。whole-numbersつまり、サンクの評価を10回強制することになります(ただし、内部的には、最適化によっては少し異なる場合があります。
•レイジーシーケンスが非常に効率的で、スタックをあまり消費しない理由は何ですか。
前の答えを読むと、これはより明確になります(私は願っています):特に何かを要求しない限り、何も評価されません。何かを呼び出すと、シーケンスの各要素を個別に評価してから破棄できます。
シーケンスが怠惰でない場合、多くの場合、それはその頭を保持しており、ヒープスペースを消費します。怠惰な場合は、後続の計算には必要ないため、計算されてから破棄されます。
•再帰呼び出しを遅延シーケンスでラップし、大規模な計算でスタックオーバーフローを発生させないようにするにはどうすればよいですか。
前の回答を参照して検討してください:lazy-seqマクロ(ドキュメントから)は
will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls.
filter再帰を使用するクールなLSの関数を確認してください。
(defn filter
"Returns a lazy sequence of the items in coll for which
(pred item) returns true. pred must be free of side-effects."
[pred coll]
(let [step (fn [p c]
(when-let [s (seq c)]
(if (p (first s))
(cons (first s) (filter p (rest s)))
(recur p (rest s)))))]
(lazy-seq (step pred coll))))
•レイジーシーケンスは、それが行うことを実行するためにどのようなリソースを消費しますか?
ここで何を求めているのかよくわかりません。LSにはメモリとCPUサイクルが必要です。彼らはスタックを強打し続けず、シーケンス要素を取得するために必要な計算の結果でスタックを埋めます。
• どのシナリオで怠惰なシーケンスが非効率的ですか?
計算が速く、あまり使用されない小さなシーケンスを使用している場合、作成するのに別の2文字が必要になるため、LSにするのは非効率的です。
真面目な話ですが、非常にパフォーマンスの高いものを作ろうとしているのでない限り、LSが最適です。
• どのシナリオでレイジーシーケンスが最も効率的ですか?
巨大なseqを扱っていて、それらの断片だけを使用している場合、それはそれらを使用することから最大の利益を得るときです。
実際、利便性、理解のしやすさ(一度コツをつかんだら)、コードについての推論、および速度の観点から、非LSよりもLSを使用する方が常に優れています。