You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何同一函数中存在loop/recur时,Clojure的for表达式无输出?

Clojure中loop/recur导致for表达式无输出的原因

函数定义代码

(defn foo []
  (let [line (apply str (repeat 2 \.))
        lines (into [] (repeat 2 line))]
    (for [x lines] (println x)) ; 此代码无输出
    (loop [remaining [[1 2] [3 4]]]
      (if (empty? remaining)
        (for [y lines] (println y)) ; 此代码有输出
        (recur (rest remaining))))))

调用foo的输出

..
..
(nil nil)

问题

预期输出应为四次..加(nil nil)。移除整个loop/recur代码块后,原无输出的for表达式可正常输出。请问为何loop/recur会导致for表达式无法生成输出?


原因解析

Clojure里的for是惰性序列生成器——它不会立刻执行里面的代码,只有当序列被"消费"(比如被遍历、打印、存入集合)的时候,才会逐个计算元素并执行对应的操作。

  1. 当函数里存在loop/recur块时:

    • 第一个(for [x lines] (println x))执行后生成了一个惰性序列,但这个序列没有被任何代码消费(既没被绑定到变量,也没作为返回值传递,更没被遍历),所以里面的println根本不会触发。
    • 函数继续执行loop/recur,直到循环结束后返回第二个for生成的惰性序列。而REPL在调用函数后会自动打印返回值,这就相当于消费了第二个惰性序列,所以里面的println会执行,输出两行..,最后打印序列本身(nil nil)(因为每个println返回nil)。
  2. 移除loop/recur块后:

    • 函数的最后一个表达式变成了第一个for,函数返回这个惰性序列。REPL自动打印返回值,消费了这个序列,所以里面的println触发,输出两行..,同时打印序列(nil nil)。

如果想让第一个for也执行,你需要主动消费它,比如用doall包裹:

(doall (for [x lines] (println x)))

这样不管它是不是最后一个表达式,都会立刻执行里面的操作。


内容的提问来源于stack exchange,提问作者user1785730

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:33:17