(fn [& args] ...)
vs.
(fn tag [& args] ...)
example stacktrace entries:
1: user$eval__3130$fn__3131.invoke(NO_SOURCE_FILE:1)
vs. ^^
1: user$eval__3138$tag__3139.invoke(NO_SOURCE_FILE:1)
^^^
(defmacro local-bindings
"Produces a map of the names of local bindings to their values."
[]
(let [symbols (map key @clojure.lang.Compiler/LOCAL_ENV)]
(zipmap (map (fn [sym] `(quote ~sym)) symbols) symbols)))
(declare *locals*)
(defn eval-with-locals
"Evals a form with given locals. The locals should be a map of symbols to
values."
[locals form]
(binding [*locals* locals]
(eval
`(let ~(vec (mapcat #(list % `(*locals* '~%)) (keys locals)))
~form))))
(defmacro debug-repl
"Starts a REPL with the local bindings available."
[]
`(clojure.main/repl
:prompt #(print "dr => ")
:eval (partial eval-with-locals (local-bindings))))
然后使用它,将其插入到您希望repl启动的任何位置:
(defn my-function [a b c]
(let [d (some-calc)]
(debug-repl)))
14 回答
还有dotrace,它允许您查看所选功能的输入和输出 .
产生输出:
在Clojure 1.4中,
dotrace
已经移动:你需要依赖:
您需要将^:dynamic添加到函数定义中
然后鲍勃又是你的叔叔:
我有一个小调试宏,我觉得非常有用:
您可以将其插入任何想要观察的内容和时间:
Emacs的CIDER有一个源调试器,您可以通过Emacs缓冲区内的表达式逐步表达,甚至注入新值 . 你可以阅读所有相关信息here . 演示截图:
Here's用于调试复杂的
let
表单的一个很好的宏:......和an essay explaining its use .
来自Java并熟悉Eclipse,我喜欢Counterclockwise(Clojure开发的Eclipse插件)提供的功能:http://doc.ccw-ide.org/documentation.html#_debug_clojure_code
我最喜欢的方法是在代码中自由地填充
println
... Turning them on and off is easy 感谢#_
阅读器宏(这使得读者以下面的形式阅读,然后假装它从未见过它) . 或者您可以使用宏扩展到传入的主体或nil
,具体取决于某些特殊变量的值,例如*debug*
:在那里有
(def *debug* false)
,这将扩展到nil
. 使用true
,它将扩展为包含在do
中的body
.这个SO问题的接受答案: Idiomatic Clojure for progress reporting? 在调试序列操作时非常有用 .
然后有一些东西是 currently incompatible with swank-clojure 的REPL,但是太好了,更不用说了: debug-repl . 您可以在独立的REPL中使用它,这很容易获得,例如与莱宁根(
lein repl
);如果你要在自己的终端上自行安装REPL . 我们的想法是你可以将debug-repl
宏放在你喜欢的任何地方,并在程序执行到达那一点时启动它自己的REPL,所有本地人都在范围内等 . 几个相关的链接:The Clojure debug-repl,Clojure debug-repl tricks,how 'bout a debug-repl(on Clojure Google小组),debug-repl on Clojars .使用Clojure代码时,swank-clojure能够使SLIME的内置调试器变得非常有用 - 请注意堆栈跟踪的不相关位是如何变灰的,因此很容易在被调试的代码中找到实际问题 . 要记住的一件事是,没有“名称标签”的匿名函数出现在堆栈跟踪中,基本上没有附加有用的信息;当添加“名称标签”时,它会出现在堆栈跟踪中,并且一切都很好:
您还可以使用Alex Osborne's debug-repl插入代码以使用所有本地绑定将自己放入REPL:
然后使用它,将其插入到您希望repl启动的任何位置:
我把它粘在我的user.clj中,所以它在所有REPL会话中都可用 .
“使用repl调试Clojure代码的最佳方法”
稍微左侧的字段,但“使用REPL iteself” .
我已经写了一年多的业余爱好者Clojure,并且对任何调试工具都没有太大的需求 . 如果你保持函数较小,并在REPL中使用预期输入运行每个函数并观察结果,那么应该可以清楚地了解代码的行为方式 .
我发现调试器对于在正在运行的应用程序中观察STATE最有用 . Clojure使用不可变数据结构(没有改变状态)的函数式编写变得简单(而且有趣!) . 这大大减少了对调试器的需求 . 一旦我知道所有组件的行为与我期望的一样(特别注意事物的类型),那么大规模行为很少成为问题 .
如果您使用emacs / slime / swank,请在REPL中尝试:
它不会给你一个完整的堆栈跟踪,就像你在LISP下得到的那样,但是它很适合探索 .
这是很好的工作:
http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml
正如上面的评论中提到的那样 .
对于IntelliJ,有一个很棒的Clojure插件叫做Cursive . 除此之外,它还提供了一个REPL,您可以在调试模式下运行并逐步执行您的Clojure代码,就像您所做的那样 . Java的 .
我会说第二个Peter Westmacott的答案,因为根据我的经验,在REPL中运行我的代码片段大部分时间都是一种充分的调试形式 .
从2016年开始,您可以使用Debux,一个用于Clojure / Script的简单调试库,它与您的repl以及浏览器控制台一起使用 . 您可以在代码中添加
dbg
(调试)或clog
(console.log)宏,并轻松观察打印到REPL和/或控制台的各个函数的结果等 .从项目的Readme:
Hugo Duncan和合作者继续为ritz项目做出惊人的工作 . Ritz-nrepl是具有调试功能的nREPL服务器 . 在Clojure / Conj 2012上观看Hugo的Debuggers in Clojure演讲,看看它在行动中,在视频中一些幻灯片是不可读的,所以你可能想要查看here的幻灯片 .
使用spyscope实现自定义读取器宏,以便您的调试代码也是 生产环境 代码https://github.com/dgrnbrg/spyscope
def-let的函数版本,它将let转换为一系列defs . 一些功劳归于here
用法:需要引用带引号的内容,例如: