[debugging] 클로저에서 디버깅? [닫은]

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 버퍼 내부의 표현식으로 표현을 수행하고 새로운 값을 주입 할 수있는 소스 디버거가 있습니다. 여기에서 모든 내용을 읽을 수 있습니다 . 데모 스크린 샷 :

CIDER 디버그


답변

내가 가장 좋아하는 방법은 println코드 전체에 자유로이 뿌리는 것입니다 . #_독자 매크로 덕분 코드를 켜고 끄는 것이 쉽습니다 (리더를 다음과 같은 형식으로 읽은 다음 본 적이없는 척). 또는 전달 된 본문으로 확장하거나 nil특수 변수의 값에 따라 매크로를 사용할 수 있습니다 *debug*.

(defmacro debug-do [& body]
  (when *debug*
    `(do ~@body)))

(def *debug* false)안에 있으면으로 확장됩니다 nil. 으로는 true, 그것은 확장 것이다 bodyA의 포장 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

위의 의견에서 언급했듯이.