当使用repl时,调试Clojure代码的最佳方法是什么?
当前回答
还有dotrace,它允许您查看所选函数的输入和输出。
(use 'clojure.contrib.trace)
(defn fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
(dotrace [fib] (fib 3))
产生输出:
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
在Clojure 1.4中,dotrace已经移动了:
你需要依赖:
[org.clojure/tools.trace "0.7.9"]
(require 'clojure.tools.trace)
您需要将^:dynamic添加到函数定义中
(defn ^:dynamic fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
那鲍勃又成了你的叔叔了
(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
其他回答
def-let的函数版本,它将一个let转换为一系列defs。有些功劳要归功于这里
(defn def-let [aVec]
(if-not (even? (count aVec))
aVec
(let [aKey (atom "")
counter (atom 0)]
(doseq [item aVec]
(if (even? @counter)
(reset! aKey item)
(intern *ns* (symbol @aKey) (eval item)))
; (prn item)
(swap! counter inc)))))
用法:需要用引文来引用内容。
(def-let '[a 1 b 2 c (atom 0)])
对于IntelliJ,有一个优秀的Clojure插件叫做Cursive。除此之外,它提供了一个REPL,你可以在调试模式下运行,并步进你的Clojure代码,就像你会在例如Java。
我同意Peter Westmacott的回答,根据我的经验,在REPL中运行我的代码片断,大多数时候是一种足够的调试形式。
下面是一个调试复杂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)))
...以及一篇解释其用途的文章。
如果你使用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
正如上面的评论所提到的。
你也可以插入代码,使用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会话中都可用。
推荐文章
- 如何为KnockoutJS调试模板绑定错误?
- 如何在构建目标之外生成gcc调试符号?
- 函数式编程有软件工程方法论吗?
- 调试器是如何工作的?
- 当有命令行参数时,如何使用GDB分析程序的核心转储文件?
- 如何在Visual Studio中找到堆栈跟踪?
- 有一个好的Valgrind Windows的替代品吗?
- Eclipse调试器总是阻塞在ThreadPoolExecutor上,没有任何明显的异常,为什么?
- Visual Studio:如何打破处理异常?
- 确保您的项目构建设置正在生成一个dSYM文件。对于所有配置,DEBUG_INFORMATION_FORMAT都应该设置为dwarf-with-dsym
- 如何获得GDB中所有线程的回溯?
- 如何检测IE11?
- 如何通过参数和重定向stdin从一个文件到程序运行在gdb?
- 如何在Clojure中创建web应用程序?
- 我如何调试git/git-shell相关的问题?