惰性序列 StackOverflowError

lazy-seq StackOverflowError

为什么这样做

(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)

生成 WhosebugError?

首先请注意,它也适用于 cons 外部:

(def fibs (cons 0 (lazy-seq (cons 1 (map + fibs (rest fibs))))))

我们还要确定 lazy-seq 是一个宏(显然,因为它不计算参数)并将 body(参数 lazy-seq)进入一个函数。

现在,如果您 "request" 该序列中的一个元素,该函数将被调用一次,后续调用将 return 缓存值。

显然,只有当那个函数 return 是你有可用值的东西时。现在,我们的坏情况发生了什么:

想象一下,clojure 正在第一次评估该函数。它首先需要的是 +fibs(rest fibs),以便将其传递给 cons。现在 clojure 将看到 fibs 是一个惰性序列并调用它!这是因为您目前处于第一次调用中,还没有 returned。这导致无限递归。

修复很简单:确保列表的开头有一个已实现的元素,这样两个表达式 fibs(rest fibs) 就可以 return 了。特别是,采用 (cons 1 whatever)rest 将 return whatever without realizing a single element (这很重要,否则我们会再次遇到同样的问题)。