在Clojure中调试?

Aru*_*n R 224 debugging clojure

使用repl时,调试Clojure代码的最佳方法是什么?

Joh*_*den 156

还有dotrace,它允许您查看所选功能的输入和输出.

(use 'clojure.contrib.trace)
(defn fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
(dotrace [fib] (fib 3))
Run Code Online (Sandbox Code Playgroud)

产生输出:

TRACE t4425: (fib 3)
TRACE t4426: |    (fib 2)
TRACE t4427: |    |    (fib 1)
TRACE t4427: |    |    => 1
TRACE t4428: |    |    (fib 0)
TRACE t4428: |    |    => 0
TRACE t4426: |    => 1
TRACE t4429: |    (fib 1)
TRACE t4429: |    => 1
TRACE t4425: => 2
2
Run Code Online (Sandbox Code Playgroud)

在Clojure 1.4中,dotrace已经移动:

你需要依赖:

[org.clojure/tools.trace "0.7.9"]
(require 'clojure.tools.trace)
Run Code Online (Sandbox Code Playgroud)

您需要将^:dynamic添加到函数定义中

(defn ^:dynamic fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
Run Code Online (Sandbox Code Playgroud)

然后鲍勃又是你的叔叔:

(clojure.tools.trace/dotrace [fib] (fib 3))

TRACE t4328: (fib 3)
TRACE t4329: | (fib 2)
TRACE t4330: | | (fib 1)
TRACE t4330: | | => 1
TRACE t4331: | | (fib 0)
TRACE t4331: | | => 0
TRACE t4329: | => 1
TRACE t4332: | (fib 1)
TRACE t4332: | => 1
TRACE t4328: => 2
Run Code Online (Sandbox Code Playgroud)

  • 从1.3开始,这已转移到clojure.tools.trace(https://github.com/clojure/tools.trace) (12认同)
  • 如果你得到:"IllegalStateException无法动态绑定非动态var",请参阅此处:http://stackoverflow.com/questions/8875353/why-im-getting-cant-dynamically-bind-non-dynamic-var (4认同)
  • 很好,但是如何找到'clojure.contrib.trace?我的classpath上有clojure-contrib jar但是REPL说`user =>(使用'closure.contrib.trace)java.io.FileNotFoundException:无法找到closure/contrib/trace__init.class或closure/contrib/trace.clj在classpath:(NO_SOURCE_FILE:0)` (2认同)
  • 你可能会错误拼写clojure作为封闭,还是评论中的拼写错误?你可以加载其他clojure.contrib库吗? (2认同)
  • 它是否也在1.5版本中工作?我正在用clojure koans学习Clojure,但是还不能让dotrace工作. (2认同)

Joh*_*den 100

我有一个小调试宏,我觉得非常有用:

;;debugging parts of expressions
(defmacro dbg[x] `(let [x# ~x] (println "dbg:" '~x "=" x#) x#))
Run Code Online (Sandbox Code Playgroud)

您可以将它插入任何想要观察的内容和时间:

;; Examples of dbg
(println (+ (* 2 3) (dbg (* 8 9))))
(println (dbg (println "yo")))
(defn factorial[n] (if (= n 0) 1 (* n (dbg (factorial (dec n))))))
(factorial 8)

(def integers (iterate inc 0))
(def squares  (map #(dbg(* % %))   integers))
(def cubes    (map #(dbg(* %1 %2)) integers squares))
(take 5 cubes)
(take 5 cubes)
Run Code Online (Sandbox Code Playgroud)

  • 更好的是:[Spyscope](https://github.com/dgrnbrg/spyscope). (4认同)
  • 非常有价值的答案,因为它需要 0 个依赖项 (2认同)

Amu*_*umu 63

Emacs的CIDER有一个源调试器,您可以通过Emacs缓冲区内的表达式逐步表达,甚至注入新值.你可以在这里阅读所有相关内容.演示截图:

CIDER调试


Mic*_*zyk 46

我最喜欢的方法是println在代码中自由地散布各种代码...... 由于读取器宏(这使得读者以下面的形式阅读,然后假装它从未见过它),打开和关闭它们很容易#_.或者您可以使用宏扩展到传入的主体或nil根据某些特殊变量的值,例如*debug*:

(defmacro debug-do [& body]
  (when *debug*
    `(do ~@body)))
Run Code Online (Sandbox Code Playgroud)

随着(def *debug* false)在那里,这将扩展到nil.随着true它,它将扩展到body包裹在do.


这个SO问题的公认答案:进展报告的惯用语Clojure?在调试序列操作时非常有用.


然后有一些东西目前与swank-clojure的REPL 不兼容,但是太好了,更不用说了:debug-repl.您可以在独立的REPL中使用它,这很容易获得,例如Leiningen(lein repl); 如果您从命令行启动程序,那么它将在您的终端中直接启用自己的REPL.我们的想法是,您可以将debug-repl宏放在任何您喜欢的地方,并在程序执行到达该点时启动它自己的REPL,所有本地人都在范围内等.几个相关链接:Clojure debug-repl,Clojure调试-repl技巧,如何在Clojars调试repl(在Clojure Google组上),调试代理.


使用Clojure代码时,swank-clojure能够使SLIME的内置调试器变得非常有用 - 请注意堆栈跟踪的不相关位是如何变灰的,因此很容易在被调试的代码中找到实际问题.要记住的一件事是,没有"名称标签"的匿名函数出现在堆栈跟踪中,基本上没有附加有用的信息; 当添加"名称标签"时,它会出现在堆栈跟踪中,并且一切都很好:

(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)
                   ^^^
Run Code Online (Sandbox Code Playgroud)

  • 实际上有一个版本的debug-repl现在可以与swank一起使用了:http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml(剧透警报:很棒) (5认同)

thn*_*tos 36

您还可以使用Alex Osborne的debug-repl插入代码将自己放入包含所有本地绑定的REPL中:

(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))))
Run Code Online (Sandbox Code Playgroud)

然后使用它,将其插入到您希望repl启动的任何位置:

(defn my-function [a b c]
  (let [d (some-calc)]
    (debug-repl)))
Run Code Online (Sandbox Code Playgroud)

我把它粘在我的user.clj中,所以它在所有REPL会话中都可用.


Pet*_*ott 15

"使用repl调试Clojure代码的最佳方法"

稍微左侧的字段,但"使用REPL iteself".

我已经写了一年多的业余爱好者Clojure,并没有对任何调试工具感到非常需要.如果你保持你的函数很小,并在REPL中使用预期输入运行每个函数并观察结果,那么应该可以非常清楚地了解代码的行为方式.

我发现调试器对于在正在运行的应用程序中观察STATE最有用.Clojure使用不可变数据结构(没有改变状态)的函数式编写变得简单(而且有趣!).这大大减少了对调试器的需求.一旦我知道所有组件的行为与我期望的一样(特别注意事物的类型),那么大规模行为很少成为问题.


Joh*_*den 9

如果您使用emacs/slime/swank,请在REPL中尝试:

(defn factorial [n]
        (cond (< n 2) n
              (= n 23) (swank.core/break)
              :else (* n (factorial (dec n)))))

(factorial 30)
Run Code Online (Sandbox Code Playgroud)

它不会像你在LISP下那样给你一个完整的堆栈跟踪,但是它很适合探索.

这是很好的工作:

http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml

正如上面的评论中提到的那样.


dsk*_*rvk 9

对于IntelliJ,有一个名为Cursive的优秀Clojure插件.除此之外,它提供了一个REPL,您可以在调试模式下运行,并像在Java中一样逐步执行Clojure代码.

我会在第二篇Peter Westmacott的回答中说,根据我的经验,在REPL中运行我的代码片段大部分时间都是一种充分的调试形式.


Mal*_*rik 6

从2016年开始,您可以使用Debux,这是一个用于Clojure/Script的简单调试库,可与您的repl和浏览器控制台配合使用.您可以在代码中撒上dbg(debug)或clog(console.log)宏,并轻松观察打印到REPL和/或控制台的各个函数的结果等.

从项目的自述文件:

基本用法

这是一个简单的例子.宏dbg打印一个原始表单,并在REPL窗口上漂亮地打印评估值.然后它返回值而不会干扰代码执行.

如果用这样的dbg包装代码,

(* 2 (dbg (+ 10 20))) ; => 60

REPL窗口中将打印以下内容.

REPL输出:

dbg: (+ 10 20) => 30

嵌套的dbg

dbg宏可以嵌套.

(dbg (* 2 (dbg (+ 10 20)))) ; => 60

REPL输出:

`dbg: (+ 10 20) => 30`  
Run Code Online (Sandbox Code Playgroud)

dbg: (* 2 (dbg (+ 10 20))) => 60


Rod*_*ada 5

Hugo Duncan和合作者继续为ritz项目做出惊人的工作.Ritz-nrepl是一款具有调试功能的nREPL服务器.观看Hugo的调试人员在Clojure的Clojure/Conj 2012演讲中看到它的实际效果,在视频中,一些幻灯片不可读,所以你可能想从这里查看幻灯片.