lazy-seq StackOverflowError

时间:2016-05-22 16:16:37

标签: clojure lazy-sequences

为什么这样做

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

1 个答案:

答案 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(重要,否则我们会再遇到同样的问题)。