【问题标题】:(println (iterate inc 0)): why does this even start printing?(println (iterate inc 0)): 为什么这甚至开始打印?
【发布时间】:2015-05-17 09:10:14
【问题描述】:

当我在我的 repl 中运行 (println (iterate inc 0)) 时,我会得到这样的结果:

user=> (println (iterate inc 0))
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 ....................

当我运行代码时,我的期望是 repl 什么都没有显示,只是卡住了,因为(iterate inc 0) 永远不会结束。但是,我看到了(0 1 2 3 ...

(iterate inc 0) 生成永不返回的无限序列。如果它永远不会结束,那为什么println 开始打印值?

换句话说,为什么即使输入从未完成评估,(println xx) 也会开始评估?

【问题讨论】:

  • println 在打印之前不需要实现整个序列,它是按需实现的。 “永远不会回来”。出于同样的原因,(first (iterate inc 0)) 会返回给您0

标签: clojure lazy-sequences


【解决方案1】:

您应该阅读 Clojure 中的 lazy seqs。它们能够产生可以在整个序列实现之前逐步消耗的值(在这种情况下,这永远不会发生)。

将其视为推与拉可能会有所帮助。不是迭代创建一个完整的值列表,然后将它们推送到 println 函数(这永远不会发生),迭代只是将其传递给一个惰性序列,然后 println 在需要时提取值。这就是 (take 5 (iterate inc 0)) 有效的原因; take 只尝试在停止前提取 5 个值。

【讨论】:

    【解决方案2】:

    Clojure 的打印比System.out.println 更智能;可以是customized for different types。在序列的情况下,walks through element-by-element, printing each one as it goes - 我们不必等到对整个序列进行评估才能开始打印。

    相比之下,System.out.println 在打印之前调用toString,其行为更像您的预期。它永远挂起,不打印任何东西,因为toString 需要评估整个序列 - 或者,至少,如果它在尝试构建字符串时没有耗尽内存,它将永远挂起。

    也就是说,整个表达式确实被卡住了 - 如果您正在等待它停止打印,您将永远等待:

    (do
      (println (iterate inc 0))
      (println "Never reached!"))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-26
      • 2013-02-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多