如何正确使用LazySeq

时间:2013-04-30 07:48:24

标签: clojure lazy-sequences

当我使用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

concatmap都会返回延迟序列,为什么上述程序看起来彼此相似却区别?

更详细地说,为什么第一个示例(lazy-seq包裹concat)失败但下面的示例(lazy-seq包裹map)成功?

1 个答案:

答案 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时调用。

希望这可以解决问题。