clojure - 在列表推导中使用 prn 或 println 进行调试
问题描述
(defn f1 []
(for [a [1 2]]
a))
;user=>(f1)
;(1 2)
(defn f2 []
(for [a [1 2]]
(prn a)))
;user=>(f2)
;1
;2
;(nil nil)
(defn f3 []
(for [a [1 2]]
(prn a))
'something-else)
;user=>(f3)
;something-else
为什么 f3 在打印“其他”之前不打印 1 和 2?
即我预期并假设(错误地)它将打印以下内容:
; 1
; 2
; something-else
当使用其中包含大量代码的 for 时遇到了这个问题,这对我尝试使用 prn 语句在调试时跟踪变量的值造成了严重破坏。即 prn 和 println 不打印出来。我认为只有当 for 块不是其封闭形式的最终形式时,但我仍然不确定发生了什么。
prn
关键是诸如or之类的副作用println
不应该需要在返回值位置才能触发。所以我不理解列表推导的更深层次的东西。
我写这篇文章时的一个概念 -f3
由于懒惰,也许在列表中的理解根本就没有被评估过?...哦[审查]。
是的,确实是这样:
(defn f4 []
(doall
(for [a [1 2]]
(prn a)))
'something-else)
user=> (f4)
;1
;2
;something-else
所以,即使大部分都解决了,我仍然会发布这个问题来巩固学习——有人愿意发布一些他们自己的问题的例子吗?懒惰。
解决方案
正如您在此处记录的那样,宏for
是惰性的,直到必须执行时才会执行。您可以通过将其包装在(vec ...)
表单或doall
.
特别是出于调试目的,我喜欢使用spyx
和forv
来自Tupelo 库来避免所有这些陷阱:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn f5 []
(forv [a [1 2]]
(spyx a))
(spy :returning :something-else))
(dotest
(spyx (f5)))
结果:
-------------------------------
Clojure 1.10.1 Java 14
-------------------------------
Testing tst.demo.core
a => 1
a => 2
:returning => :something-else
(f5) => :something-else
Ran 2 tests containing 1 assertions.
0 failures, 0 errors.
所以你可以看到打印得很好:
- 循环
a
每一步的标记值。forv
- 带有自定义标签的函数的返回值
- 函数调用的显式值
(f5)
- 没有什么地方是懒惰的
spy
,spyx
, et al 总是返回打印的值以供进一步使用- 一个方便的单元测试通过
is=
确认输出值。
有一个不错的模板项目,您可以克隆它以帮助您快速入门。
您可能还对with-result或 just感兴趣doseq
。不要忘记Clojure CheatSheet。
推荐阅读
- cassandra - Can Cassandra be used to both replicate, provide a 'master' and filter data at sites?
- django - 从模型中显示(在模板中)选择 - Django
- asynchronous - Nifi 处理器可高效处理异步任务
- date - 在 Perl 6 中查找上周五的日期?
- selenium - WebElement 在开发者控制台中通过 xpath 识别,但元素不会通过 selenium findElement 方法识别
- .net-core - 如何在 ASP.NET Core 2 中处理数据库上的多个表
- jquery - 从另一个 .js 中应用于 API 的函数获取结果
- java - 构造函数类错误?
- java - Hibernate Enver 不审核软删除中使用的字段?
- r - R lag 在带有计数器变量的循环中不起作用?