为什么不执行for函数

  • 本文关键字:for 函数 执行 clojure
  • 更新时间 :
  • 英文 :


我是clojure的初学者,有一个困惑的问题:

(do (println "ok") (for [x [1 2 3]] (println x)))

输出:好吧123

我能理解,但是


(do (for [x [1 2 3]] (println x)) (println "ok"))

输出:好吧nil

为什么for函数没有被执行?

示例中的(println x)形式是副作用,只有在实现for惰性序列时才会发生。

下面是第一个重新格式化的例子:

(do
(println "ok")
(for [x [1 2 3]]
(println x)))

do依次求值并返回最后一个表达式的值。这里的最后一个表达式是一个惰性序列。如果您在REPL中对其进行计算,则惰性序列将实现打印其元素(给定值(nil nil nil))并导致打印123的副作用。

下面是第二个重新格式化的例子:

(do
(for [x [1 2 3]]
(println x))
(println "ok"))

再次,do依次求值表达式。第一个是惰性序列,但它的值没有被使用,因此永远不会实现。这意味着不会出现打印123的副作用。

简而言之:do宏计算所有参数并返回最后一个参数的值,这迫使惰性序列的元素实现。

我假设您在REPL中计算了两个表达式。

由于for宏,第一个表达式返回一个惰性序列。REPL强制对返回值进行求值(这样它就可以显示求值的结果),因此序列的每个元素都实现了打印到屏幕上的副作用。

在第二种情况下,返回值是nil,因为do形式中的最后一个表达式是println调用。在这种情况下也创建了惰性序列,但它的元素永远不会实现,因为它的值永远不会被使用。

如果你想强制求值一个序列,你可以使用doall或dorun。如果对序列不感兴趣,只需要一个循环结构,可以使用doseq代替for。

其他答案已经提供了很好的背景。如果您需要for的高级特性,但又不想要惰性方面,只需将整个内容包装在(vec ...)表单中:

(vec (for [x [1 2 3]]
(println x)))

这已经在forv宏中为您完成了,可以在这里看到。

最新更新