IT story

클로저에서 디버깅?

hot-time 2020. 4. 20. 20:33
반응형

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


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 년 넘게 취미 애호가 Clojure를 작성해 왔으며 디버깅 도구가 크게 필요하지 않았습니다. 함수를 작게 유지하고 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에서 내 코드 조각을 실행하는 것은 대부분 충분한 형태의 디버깅입니다.


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를 사용 하십시오.


복잡한 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)))

... 그리고 사용법을 설명하는 에세이 .


Java에서 왔고 Eclipse에 익숙해지면 Counterclockwise (Clojure 개발 용 Eclipse 플러그인)가 제공하는 것을 좋아합니다. http://doc.ccw-ide.org/documentation.html#_debug_clojure_code


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)])

참고 URL : https://stackoverflow.com/questions/2352020/debugging-in-clojure

반응형