我正在尝试以一种懒惰的方式解决Project Euler 问题 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 的堆栈溢出,如果您考虑一下为什么它需要在 n=3 时“展望未来”以了解惰性列表中第十个元素的值,这是可以理解的,因为 (+ 1 (* 3 n)) = 10。
由于惰性列表的开销比记忆小得多,我想知道这种事情是否可以通过更延迟的评估或排队以某种方式实现?