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


当前回答

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

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

你可以把它插入到任何你想看发生了什么和什么时候:

;; 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)

其他回答

对于IntelliJ,有一个优秀的Clojure插件叫做Cursive。除此之外,它提供了一个REPL,你可以在调试模式下运行,并步进你的Clojure代码,就像你会在例如Java。

我同意Peter Westmacott的回答,根据我的经验,在REPL中运行我的代码片断,大多数时候是一种足够的调试形式。

如果你使用emacs/slime/swank,那么在REPL试试这个:

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

(factorial 30)

它不像在LISP下那样为您提供完整的堆栈跟踪,但它很适合进行探查 周围。

这是优秀的工作:

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

正如上面的评论所提到的。

下面是一个调试复杂let表单的宏:

(defmacro def+
  "def with binding (def+ [{:keys [a b d]} {:a 1 :b 2 :d 3}])"
  [bindings]
  (let [let-expr (macroexpand `(let ~bindings))
        vars (filter #(not (.contains (str %) "__"))
               (map first (partition 2 (second let-expr))))
        def-vars (map (fn [v] `(def ~v ~v)) vars)]
    (concat let-expr def-vars)))

...以及一篇解释其用途的文章。

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

稍微偏左,但是“使用REPL本身”。

我写Clojure已经有一年多的时间了,并没有觉得对任何调试工具有很大的需求。如果你保持你的函数很小,并且在REPL中运行每个函数,并观察结果,那么你应该可以非常清楚地了解你的代码是如何行为的。

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

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

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

你可以把它插入到任何你想看发生了什么和什么时候:

;; 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)