답변:
선택한 기능의 입력 및 출력을 볼 수있는 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
user=> (use 'closure.contrib.trace) java.io.FileNotFoundException: Could not locate closure/contrib/trace__init.class or closure/contrib/trace.clj on classpath: (NO_SOURCE_FILE:0)
매우 유용한 디버깅 매크로가 있습니다.
;;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)
clojure.tools.trace/trace
합니다.
내가 가장 좋아하는 방법은 println
코드 전체에 자유로이 뿌리는 것입니다 . #_
독자 매크로 덕분 에 코드를 켜고 끄는 것이 쉽습니다 (리더를 다음과 같은 형식으로 읽은 다음 본 적이없는 척). 또는 전달 된 본문으로 확장하거나 nil
특수 변수의 값에 따라 매크로를 사용할 수 있습니다 *debug*
.
(defmacro debug-do [& body]
(when *debug*
`(do ~@body)))
이 (def *debug* false)
안에 있으면으로 확장됩니다 nil
. 으로는 true
, 그것은 확장 것이다 body
A의 포장 do
.
이 SO 질문에 대한 대답 : 진행 상황보고를위한 관용적 Clojure? 시퀀스 작업을 디버깅 할 때 매우 유용합니다.
그런 다음 swank-clojure 의 REPL 과 현재 호환되지 않는 것이 있지만 언급하지 않는 것이 좋습니다 debug-repl
. Leiningen ( lein repl
) 을 사용하면 쉽게 얻을 수있는 독립 실행 형 REPL에서 사용할 수 있습니다 . 명령 줄에서 프로그램을 시작하면 터미널에 자체 REPL이 표시됩니다. 아이디어는 당신이 떨어질 수 있다는 것입니다 debug-repl
당신처럼 어디에서 매크로를하고 자신의 REPL을 가지고있을 때 범위에있는 모든 주민 등 관련 링크의 부부와 함께 프로그램의 실행에 도달 그 시점 : Clojure의 디버그 - REPL , Clojure의 디버그 -repl 트릭 , 어떻게 '디버그 - REPL의 한판 승부 합니다 (Clojure의 구글 그룹에), Clojars에 디버그 REPL .
swank-clojure는 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)
^^^
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)))
내 user.clj 에이를 붙여서 모든 REPL 세션에서 사용할 수 있습니다.
"repl을 사용하는 동안 Clojure 코드를 디버깅하는 가장 좋은 방법"
약간 왼쪽 필드이지만 'REPL 항목 사용'.
나는 1 년 넘게 취미 애호가 클로저를 작성해 왔으며 디버깅 도구가 크게 필요하지 않았습니다. 함수를 작게 유지하고 REPL에서 예상되는 입력으로 각 기능을 실행하고 결과를 관찰하면 코드의 작동 방식을 매우 명확하게 파악할 수 있습니다.
디버거가 실행중인 응용 프로그램에서 STATE를 관찰하는 데 가장 유용하다는 것을 알았습니다. Clojure를 사용하면 변경 불가능한 데이터 구조로 상태를 변경하지 않고도 기능적인 스타일로 쉽게 작성할 수 있습니다. 이것은 디버거의 필요성을 크게 줄입니다. 모든 구성 요소가 예상대로 작동한다는 것을 알면 (사물 유형에 특히주의를 기울임) 대규모 동작은 거의 문제가되지 않습니다.
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
위의 의견에서 언급했듯이.
IntelliJ에는 Cursive 라는 훌륭한 Clojure 플러그인이 있습니다. 무엇보다도 디버그 모드에서 실행하고 Java와 같이 Clojure 코드를 단계별로 실행할 수있는 REPL을 제공합니다.
Peter Westmacott의 대답을 두 번째로 생각하지만 REPL에서 내 코드 조각을 실행하는 것은 대부분 충분한 형태의 디버깅입니다.
Leiningen
은 다음 과 같습니다.Error running 'ring server': Trampoline must be enabled for debugging
ring
이거나 lein
아마도 별도의 질문을 게시 할 가치가 있는 것 같습니다 .
2016 년 현재 , Rebu 및 브라우저 콘솔과 함께 작동하는 Clojure / Script 용 간단한 디버깅 라이브러리 인 Debux 를 사용할 수 있습니다 . 코드에 dbg
(디버그) 또는 clog
(console.log) 매크로를 뿌릴 수 있으며 REPL 및 / 또는 콘솔에 인쇄 된 개별 기능 등의 결과를 쉽게 관찰 할 수 있습니다.
프로젝트의 Readme에서 :
기본 사용법
이것은 간단한 예입니다. 매크로 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`
dbg: (* 2 (dbg (+ 10 20))) => 60
휴고 던컨 (Hugo Duncan)과 협력자들은 리츠 프로젝트로 계속해서 놀라운 일을하고 있습니다. Ritz-nrepl 은 디버그 기능이있는 nREPL 서버입니다. Clojure 의 Hugo 's Debuggers가 Clojure / Conj 2012에서 대화를보고 실제로 작동하는 모습을보고 비디오에서 일부 슬라이드를 읽을 수 없으므로 여기 에서 슬라이드를 볼 수 있습니다 .
디버그 코드가 프로덕션 코드 https://github.com/dgrnbrg/spyscope 가되도록 사용자 지정 판독기 매크로를 구현하는 spyscope를 사용 하십시오.
Java에서 왔고 Eclipse에 익숙해지면 Counterclockwise (Clojure 개발 용 Eclipse 플러그인)가 제공하는 것을 좋아합니다. http://doc.ccw-ide.org/documentation.html#_debug_clojure_code
복잡한 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)))
... 그리고 사용법을 설명하는 에세이 .
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)])