为什么这样做
(def fibs (cons 0 (cons 1 (lazy-seq (map + fibs (rest fibs))))))
(take 10 fibs)
而另一个
(def fibs (lazy-seq (cons 0 (cons 1 (map + fibs (rest fibs))))))
(take 10 fibs)
生成StackOverflowError?
答案 0 :(得分:4)
首先请注意,它也适用于一个cons
外:
(def fibs (cons 0 (lazy-seq (cons 1 (map + fibs (rest fibs))))))
让我们确定lazy-seq
是一个宏(显然,因为它不评估参数)并将body
(参数设置为lazy-seq
)放入功能
现在,如果您“请求”该序列中的一个元素,该函数将被调用一次,后续调用将返回缓存的值。
显然,只有一次该函数返回一些你有值的东西。现在,在我们的坏情况下发生了什么:
想象一下,clojure第一次正在评估这个功能。它需要的第一件事是+
,fibs
和(rest fibs)
,以便将其传递给cons。现在,clojure会看到fibs
是一个懒惰的序列并调用它!这是因为您目前正处于第一次调用中并且尚未返回。这导致无限递归。
修复很简单:确保列表开头有一个已实现的元素,以便两个表达式fibs
和(rest fibs
)可以返回一些内容。特别是,取rest
(cons 1 whatever)
将返回whatever
without realizing a single element(重要,否则我们会再遇到同样的问题)。