私はプロジェクトオイラー問題14を怠惰な方法で解決しようとしています。残念ながら、私は不可能なことをしようとしているかもしれません。両方とも怠惰な怠惰なシーケンスを作成しますが、まだ計算されていない値をどういうわけか「先読み」します。
正確さをテストするために私が書いた非遅延バージョンは次のとおりです。
(defn chain-length [num]
(loop [len 1
n num]
(cond
(= n 1) len
(odd? n) (recur (inc len) (+ 1 (* 3 n)))
true (recur (inc len) (/ n 2)))))
これは機能しますが、本当に遅いです。もちろん、私はそれを覚えることができます:
(def memoized-chain
(memoize
(fn [n]
(cond
(= n 1) 1
(odd? n) (+ 1 (memoized-chain (+ 1 (* 3 n))))
true (+ 1 (memoized-chain (/ n 2)))))))
しかし、私が本当にやりたかったのは、怠惰なシーケンスの限界を理解するためにかゆみを掻き、次のような関数を書くことでした。
(def lazy-chain
(letfn [(chain [n] (lazy-seq
(cons (if (odd? n)
(+ 1 (nth lazy-chain (dec (+ 1 (* 3 n)))))
(+ 1 (nth lazy-chain (dec (/ n 2)))))
(chain (+ n 1)))))]
(chain 1)))
これから要素をプルすると、n> 2のスタックオーバーフローが発生します。これは、レイジーリストの10番目の要素の値を知るためにn=3で「将来を見据える」必要がある理由を考えると理解できます。 1(* 3 n))=10。
怠惰なリストはメモ化よりもはるかにオーバーヘッドが少ないので、この種のことが、さらに遅延した評価またはキューイングによって何らかの形で可能かどうかを知りたいですか?