В данной статье хочу рассказать о некоторых методах отладки в clojure.
Метод 1. Использование точек останова в slime.
При использовании emacs появляется возможность устранавливать точки останова(breakpoints), что позволяет
просматривать стек вызовов и локальные переменные. Для установки используется функция swank.core/break Рассмотрим небольшой пример:
(defn add [a b]
(swank.core/break)
(+ a b))
Вызовем данную функцию из repl: (add 1 2) =>BREAK:
[Thrown class java.lang.Exception]
Restarts:
0: [QUIT] Quit to the SLIME top level
1: [CONTINUE] Continue from breakpoint
Backtrace:
0: debug.core$add.invoke(core.clj:4)
1: debug.core$eval1851.invoke(NO_SOURCE_FILE:1)
2: clojure.lang.Compiler.eval(Compiler.java:6465)
3: clojure.lang.Compiler.eval(Compiler.java:6431)
4: clojure.core$eval.invoke(core.clj:2795)
--more--
При наведении курсора на строку 0: debug.core$add.invoke(core.clj:4) и нажатии enter, получим:
BREAK:
[Thrown class java.lang.Exception]
Restarts:
0: [QUIT] Quit to the SLIME top level
1: [CONTINUE] Continue from breakpoint
Backtrace:
0: debug.core$add.invoke(core.clj:4)
Locals:
a = 1
b = 2
1: debug.core$eval1851.invoke(NO_SOURCE_FILE:1)
2: clojure.lang.Compiler.eval(Compiler.java:6465)
3: clojure.lang.Compiler.eval(Compiler.java:6431)
4: clojure.core$eval.invoke(core.clj:2795)
--more--
При нажатии enter на локальной переменной запустится инспектор slime.
При нажатии клавиши 1 - функция продолжит свое выполнение.
Метод 2. Трассировка.
В данном методе отладки используется модуль clojure.contrib.trace.
Важно! При использовании версии clojure 1.3 необходимо указывать ^:dynamic при определении функций для трассировки.
Пример:
(use 'clojure.contrib.trace)
(deftrace sub [a b] (- a b))
(deftrace sub-2 [a b] (- b a))
(defn func [a b]
(+ (sub a b) (sub-2 a b))
Результат вызова:(func 1 2)=>
TRACE t1964: (sub 1 2)
TRACE t1964: => -1
TRACE t1965: (sub-2 1 2)
TRACE t1965: => 1
0
Макрос deftrace выводит название функции, ее аргументы и результат выполнения.
Подробнее про данный модуль можно прочитать тут(trace-api)
Метод 3. Использование отладочного вывода.
В данном случае существует множество методик от простого использование функции print до сложных макросов. Одним из вариантов может служить такой пример:
(defmacro debug-do [& body]
(when *debug*
`(do ~@body))
Такой способ позволяет включать отладочный режим установкой переменной *debug* в true.Пример использования:
(def *debug* 1)
(defmacro debug-do [& body]
(when *debug*
`(do ~@body))
(defn add-2 [a b]
(debug-do (printf "a = %d\n" a)
(printf "b = %d\n" b)
(flush))
(+ 1 2))
При вызове этой функции в repl получаем:(add-2 1 2)=>
a = 1
b = 2
3