在for循环中打印

时间:2019-03-23 20:04:57

标签: clojure

我正在练习一个Clojure教程,必须确保执行了一个for循环,所以我在此处放置了一个println命令,但是它不显示消息。

所以现在我有一个问题...

此代码显示汤姆的名字:

(ns tutorial.core)
(defn -main []
  (println 'Jane)
  (for [a ['Tom]]
    (println a))
;;    'Kate
)



tutorial.core> (-main)
Jane
Tom
(nil)
tutorial.core> 

但不是:

(ns tutorial.core)
(defn -main []
  (println 'Jane)
  (for [a ['Tom]]
    (println a))
    'Kate
)


tutorial.core> (-main)
Jane
Kate
tutorial.core>

为什么?在哪种情况下,我们可以预期println将不会打印文本?

2 个答案:

答案 0 :(得分:1)

+------------+--------------+-------------------+------------+ | Id | Product Name | Categories | Price | +------------------------------------------------------------+ | 1 | cola | Drink, Fat | 1 | | 2 | burger | Food, Fat | 4 | +------------------------------------------------------------+ 不是循环,而是序列理解,它返回惰性序列。因此,当计算返回的序列时,您的for表达式将仅执行其副作用(对for的调用)。 REPL会评估您对println的调用返回的值,以便可以打印它们。

您的第一个示例返回一个惰性序列,该序列由REPL评估,从而导致对-main调用的评估。由于(println 'Tom)返回println,因此结果序列包含单个nil值-这就是您在输出中看到的nil

您的第二个示例创建了相同的序列,但未求值,而是从该函数返回了(nil),REPL打印了该序列。

如果您需要强制性的for循环,则应使用'Kate

doseq

答案 1 :(得分:1)

正如Lee所说,如果您只想要打印之类的副作用,doseq是最好的解决方案,因为它永远不会返回nil以外的值。

如果您确实想使用for循环,则可以通过将其包装在(vec ...)表达式中来消除延迟,这将强制for循环立即运行。这样我们得到:

(println :start)
(vec
  (for [a [1 2 3]]
    (println a)))
(println :end)

结果:

:start
1
2
3
:end

没有vec,我们得到的是您看到的行为:

(println :start)
(for [a [1 2 3]]
  (println a))
(println :end)

结果:

:start
:end

我几乎永远都不会想要一个懒惰的结果,因为何时的不确定性会使调试变得困难。我经常使用上述构造,以至于我写了a small macro forv,总是返回矢量结果,类似于mapv函数。