惰性序列 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 (这很重要,否则我们会再次遇到同样的问题)。
为什么这样做
(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 (这很重要,否则我们会再次遇到同样的问题)。