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


当前回答

来自Java并且熟悉Eclipse,我喜欢逆时针(用于Clojure开发的Eclipse插件)提供的功能:http://doc.ccw-ide.org/documentation.html#_debug_clojure_code

其他回答

Hugo Duncan和他的合作者继续在ritz项目上做着惊人的工作。Ritz-nrepl是一个具有调试功能的nREPL服务器。在Clojure/Conj 2012上观看Hugo's Debuggers in Clojure talk来查看它的实际操作,在视频中一些幻灯片是不可读的,所以你可能想从这里查看幻灯片。

如果你使用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

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

Emacs的CIDER有一个源调试器,您可以在Emacs缓冲区中逐步执行表达式,甚至可以注入新值。你可以在这里读到所有的信息。演示截图:

下面是一个调试复杂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)))

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

你也可以插入代码,使用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))))

然后要使用它,将它插入到你想要repl开始的地方:

(defn my-function [a b c]
  (let [d (some-calc)]
    (debug-repl)))

我把这个插入我的用户。clj,所以在所有REPL会话中都可用。