当我使用lazySeq时,有十几个混乱。
问题:
(def fib
(lazy-seq
(concat [0 1] (map + fib (rest fib))))) ;; It's Ok
(take 10 fib) ;; Bomb
收到错误消息: StackOverflowError clojure.lang.RT.more(RT.java:589)
以下解决方案效果很好:
(def fib
(concat [0 1] (lazy-seq (map + fib (rest fib))))) ;; Works well
(def fib
(lazy-cat [0 1] (map + fib (rest fib)))) ;; Works well
concat
和map
都会返回延迟序列,为什么上述程序看起来彼此相似却区别?
更详细地说,为什么第一个示例(lazy-seq
包裹concat
)失败但下面的示例(lazy-seq
包裹map
)成功?
答案 0 :(得分:3)
问题是在地图操作中使用rest
。基本上,当你的lazy-seq调用表达式(concat [0 1] (map + fib (rest fib)))
来返回一个ISeq对象时,会发生rest
对fib的调用(因为这是map
的参数,必须先执行然后传递到地图和地图是懒惰的,但在我们达到懒惰之前调用休息)。 rest
将尝试在作为LazySeq
对象的fib上调用more
,并且更多将导致fib lazy seq获取下一个ISeq,这再次涉及整个{{1涉及concat
的操作,它继续这样,直到堆栈被吹走。
你需要使用不会立即调用的内容,例如rest
:
drop
此外,在(def fib
(lazy-seq
(concat [0 1] (map + fib (drop 1 fib)))))
位于lazy-seq
内的其他情况下,concat
未执行,因为它被包装在rest
操作中,这使得整个表达式成为一个函数在将来请求下一个ISeq时调用。
希望这可以解决问题。