在类似 (do (for (link: x (do (println "realized") nil)) x) nil) 的调用中,for 结果表达式中的任何元素从未被请求过,因此实际上没有必要评估内部 do 块。然而,此表达式会导致打印出 "realized",因为在 for 中,即使从未从输出惰性序列中请求任何项,也会评估第一个序列表达式。
没有文档记录这是预期的还是意外的,但这个行为让我感到惊讶,而且一个关于 #clojure 的简短非科学调查表明,其他用户,即使是已经使用 clojure 好几年的 "老手",也不期望这种行为。
我附带了一个补丁,它会将问题表达式包装在一个 lazy-seq 调用中。这并不完全理想,因为这意味着第一个迭代被 "惰化"了两遍,就像 ((fn step (link: s) (lazy-seq ...)) (lazy-seq xs)) 一样,但改变让它不发生的改动范围会更广,而且这似乎是最安全的。