在欧拉项目的problem 3上我尝试了这个:
(defn range-start-2 [] (map #(+ % 2) (range)))
(defn largest-prime
"Finds the largest prime factor of n. (n must be >= 2)"
[n largest-prime unchecked]
(cond
(> (first unchecked) n)
largest-prime
(= (mod n (first unchecked)) 0)
(recur n (first unchecked) (filter #(not= (mod % (first unchecked)) 0) unchecked))
:else
(recur n largest-prime (filter #(not= (mod % (first unchecked)) 0) unchecked))))
(largest-prime (* 3 7 11 13) 2 (range-start-2))
;=> 13
这适用于小n但是给了我更大的n的堆栈溢出。我假设我正在坚持未经检查的seq的头部,但我无法弄清楚在哪里。使用它作为参数不应该留在头上,是吗?
我读到关闭懒惰的seq可能导致头被关闭,所以我尝试了这个:
(defn largest-prime
"Finds the largest prime factor of n."
[n largest-prime unchecked]
(let [prime (first unchecked)]
(cond
(> prime n)
largest-prime
(= (mod n prime) 0)
(recur n prime (filter #(not= (mod % prime) 0) unchecked))
:else
(recur n largest-prime (filter #(not= (mod % prime) 0) unchecked)))))
这也不起作用。必须有一种方法来获取lazy-seq的第一个元素的值,而不必坚持它的头部。
(当然有更好的方法来解决欧拉项目问题,但在这里我只对头部控股问题感兴趣)
答案 0 :(得分:4)
您的问题是filter
来电是“堆积”未评估的。 filter
未立即应用,但在您从序列中请求元素时应用。当你积累(filter f1 (filter f2 (filter f3 ... (filter f1000 s)...)))
时,它会进行一千次深度调用,最终会出现堆栈溢出。
解决方案是不以这种方式使用无限延迟序列。 (如果您的序列是有限的,则可以使用doall
避免堆栈溢出。)
请注意,有一些优化可能会使您的问题的其他方法可行。如果您知道3,7和11是3003的因子,那么您实际上不需要检查11到3003之间的所有可能的素数......