【问题标题】:lazy-seq StackOverflowError惰性序列 StackOverflowError
【发布时间】:2016-09-19 11:43:04
【问题描述】:

为什么会这样

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

【问题讨论】:

  • 您想通过lazy-seq 实现什么目标?如果您将其删除,它似乎运行良好。
  • @jmargolisvt 在我的 repl (clojure 1.6) 上,代码 ` (def fibs (cons 0 (cons 1 (map + fibs (rest fibs)))))` 不起作用。我认为 Lazy-seq 是必要的,因为它会延迟流的计算,否则它将无法根据 fibs 本身定义 fibs

标签: clojure lazy-sequences


【解决方案1】:

首先我们要注意,它也适用于外部cons

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

让我们还确定lazy-seq 是一个宏(显然,因为它不评估参数)并将bodylazy-seq 的参数)放入一个函数中。

现在,如果您从该序列中“请求”一个元素,该函数将被调用一次,随后的调用将返回缓存值。

显然,只有在该函数返回某些内容时,您才有可用的值。现在,在我们的坏案例中发生了什么:

想象一下 clojure 正在第一次评估函数。它需要的第一件事是+fibs(rest fibs),以便将其传递给 cons。现在 clojure 将看到 fibs 是一个惰性序列并调用它!这是因为您当前处于第一次调用中并且尚未返回。这会导致无限递归。

解决方法很简单:确保列表开头有一个已实现的元素,以便两个表达式 fibs(rest fibs) 可以返回一些内容。特别是,使用(cons 1 whatever)rest 将返回whatever without realizing a single element(很重要,否则我们会再次遇到同样的问题)。

【讨论】:

    猜你喜欢
    • 2014-11-10
    • 1970-01-01
    • 2012-03-01
    • 2011-07-21
    • 2023-02-05
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 2010-12-08
    相关资源
    最近更新 更多