最初に注意すべきことは、コード自体は何もしないということです。これは単なる数式の集まりであり、それらから何らかの値を抽出しようとするまで、それがどれほど循環的であるかは問題ではありません。どうやってそれを行うのですか?
できること:
print $ take 1 primes1
ここは問題ありません。再帰コードを見なくても、primes1 の最初の値を取得できます。明示的に 2 として存在します。
print $ take 3 primes1
primes1
いくつかの値を取得するために展開してみましょう。これらの式を管理しやすくするために、ここではprint
andtake
の部分を無視していますが、この作業を行っているのはそれらがあるためだけであることを覚えておいてください。primes1
は:
primes1 = 2 : filter prime [3..]
最初の値があり、2 番目への最初のステップはフィルターの展開です。これが厳密な言語である場合、最初に [3..] を拡張しようとして行き詰まります。可能なフィルターの定義は次のとおりです。
filter f (x:xs) = if f x then x : filter f xs else filter f xs
これは次を与えます:
primes1 = 2 : if prime 3 then 3 : filter prime [4..] else filter prime [4..]
次のステップは、が真か偽かを判断する必要があるため、とprime 3
の定義を使用して展開してみましょう。prime
ldp
ldpf
primes1 = 2 : if ldp 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
primes1 = 2 : if ldpf primes1 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
ここで興味深いことに、primes1 は自分自身を参照し、ldpf はその計算を行うために最初の値を必要とします。幸いなことに、最初の値は簡単に取得できます。
primes1 = 2 : if ldpf (2 : tail primes) 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
ここで、ldpf と find にガード句を適用し2^2 > 3
ますldpf (2 : tail primes) 3 = 3
。
primes1 = 2 : if 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
primes1 = 2 : 3 : filter prime [4..]
これで 2 番目の値が得られました。評価の右辺が特に大きくなることはなく、再帰ループを遠くまでたどる必要がないことに注意してください。
primes1 = 2 : 3 : if prime 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : if ldp 4 == 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : if ldpf primes1 4 == 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : if ldpf (2 : tail primes1) 4 == 4 then 4 : filter prime [5..] else filter prime [5..]
ガード節を使用するため、rem 4 2 == 0
ここでは 2 が得られます。
primes1 = 2 : 3 : if 2 == 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : filter prime [5..]
primes1 = 2 : 3 : if prime 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldp 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldpf primes1 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldpf (2 : tail primes) 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
ガード マッチがないため、次のように再帰します。
primes1 = 2 : 3 : if ldpf (tail primes) 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldpf (3 : tail (tail primes)) 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
その3^2 > 5
式は 5 です。
primes1 = 2 : 3 : if 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : 5 : filter prime [6..]
必要な値は 3 つだけなので、評価を停止できます。
それで、今あなたの質問に答えます。遅延リストは、必要なものを評価するだけでよいリストであり、再帰ステップに到達したときに常に十分な値が計算済みであることを保証するため、この 2 が役立ちます。(2 がわからない場合に式を展開すると、すぐにループに陥ってしまうことを想像してください。)