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
답변
매우 유용한 디버깅 매크로가 있습니다.
;;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)
답변
Emacs의 CIDER에는 Emacs 버퍼 내부의 표현식으로 표현을 수행하고 새로운 값을 주입 할 수있는 소스 디버거가 있습니다. 여기에서 모든 내용을 읽을 수 있습니다 . 데모 스크린 샷 :
답변
내가 가장 좋아하는 방법은 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
위의 의견에서 언급했듯이.