我正在练习一个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
将不会打印文本?
答案 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
函数。