Clojureでのデバッグ?[閉まっている]


227

replを使用しているときにClojureコードをデバッグする最良の方法は何ですか?


以下の回答に加えて、REPLガイドの「デバッグツールとテクニック」を参照してください。clojure.org
Valentin Waeselynck

回答:


158

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

2
いいですが、clojureで「clojure.contrib.trace」を見つけるにはどうすればよいですか?私はクラスパスにclojure-contrib jarを持っていますが、REPLは言う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)
LarsH

2
clojureをクロージャーとしてつづりを間違えていませんか、それともコメントのタイプミスですか?他のclojure.contribライブラリをロードできますか?
John Lawrence Aspden、2009

12
1.3以降、これはclojure.tools.trace(github.com/clojure/tools.trace)に移動しました
George

4
あなたが取得している場合:「IllegalStateExceptionが缶動的に結合しない非動的varが」ここを参照してください:stackoverflow.com/questions/8875353/...
コーネリアス

2
1.5リリースでも機能していますか?Clojure KoansでClojureを学習していますが、まだdotraceを機能させることができません。
nha 2014年

100

私は非常に便利な小さなデバッグマクロを持っています。

;;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ます。
Zaz

4
さらに良い:Spyscope
Zaz

@Zaz私は完全に同意します。Spyscopeは素晴らしいです!たぶんデバッガよりも良いでしょう。確かにタイピング用です。
J Atkin

66

EmacsのCIDERには、Emacsバッファー内で式ごとにステップ実行できるソースデバッガーがあり、新しい値を挿入することもできます。あなたはそれについてここですべて読むことができます。デモのスクリーンショット:

CIDERデバッグ


46

私のお気に入りの方法はprintln、コード全体にsを自由に振りかけることです... リーダーマクロのおかげで、オンとオフを簡単に切り替えることができ#_ます(これにより、リーダーは次の形式で読み取られ、見られないふりをします)。または、渡された本体に拡張するか、またはnilいくつかの特殊変数の値に応じて、次のように拡張するマクロを使用できます*debug*

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

(def *debug* false)そこに、これはに拡大していきますnil。を使用するとtrue、にbody包まれて展開されますdo


このSOの質問に対する受け入れられた回答:進行状況レポートのための慣用的なClojure?シーケンス操作をデバッグするときに非常に役立ちます。


次に、現在swank-clojureのREPL と互換性のないものがありますが、言うまでもありませんdebug-repl。スタンドアロンREPLで使用できます。これは、たとえばLeiningen(lein repl)で簡単に取得できます。コマンドラインからプログラムを起動している場合は、ターミナルで独自のREPLを起動します。アイデアは、debug-replマクロを好きな場所にドロップして、プログラムの実行がそのポイントに達したときに、すべてのローカルがスコープ内にあるなど、独自のREPLを表示させることができるというものです。関連するリンクのカップル:Clojure debug-replClojure debug -replトリックどのように「デバッグ・REPL試合(ClojureのGoogleのグループに)、ClojarsのデバッグREPL


swank-clojureは、Clojureコードを操作するときにSLIMEの組み込みデバッガーを便利にする適切な役割を果たします-スタックトレースの無関係なビットが灰色になっているので、デバッグ中のコードで実際の問題を簡単に見つけることができます。覚えておくべきことの1つは、「名前タグ」のない無名関数はスタックトレースに表示され、基本的に有用な情報が付加されていないことです。「名前タグ」が追加されると、スタックトレースに表示され、すべて順調です。

(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)
                   ^^^

5
実際、swankで動作するdebug-replのバージョンがあります:hugoduncan.org/post/2010/… (スポイラーアラート:それは素晴らしい)

1
そうです、ここにリンクを張っておくのは良いことです、ありがとう!素晴らしいことに同意しました。:-)
のMichałMarczyk

これが自分のスタイルである場合、後続の応答で言及されているdebuxライブラリが好きかもしれません。github.com/philoskim/debux
Mallory-Erik

@ Mallory-Erikよろしくお願いします!
のMichałMarczyk

37

Alex Osbornedebug-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セッションで使用できるようにします。


16

"replを使用しながらClojureコードをデバッグする最良の方法"

少し左のフィールドですが、「REPL iteselfを使用する」。

私は1年以上趣味のClojureを書いていて、デバッグツールの必要性を感じていません。関数を小さく保ち、REPLで期待される入力を使用して各関数を実行し、結果を観察すると、コードの動作をかなり明確に把握できるはずです。

デバッガーは、実行中のアプリケーションでSTATEを監視するのに最も役立ちます。Clojureを使用すると、不変のデータ構造(状態を変更しない)を使用した関数スタイルで簡単に(そして楽しく!)作成できます。これにより、デバッガの必要性が大幅に減少します。すべてのコンポーネントが期待どおりに動作することがわかったら(種類に特に注意を払います)、大規模な動作が問題になることはほとんどありません。


これはほとんどの場合当てはまりますが、たとえば複数の関数に再帰がある場合、それほど簡単ではありません。
ジョン

9

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

上記のコメントで述べたように。


9

IntelliJには、Cursiveと呼ばれる優れたClojureプラグインがあります。。とりわけ、それはデバッグモードで実行し、Javaの場合と同じようにClojureコードをステップ実行できるREPLを提供します。

私の経験では、REPLでコードの一部を実行するだけでほとんどの場合デバッグの十分な形式になりますが、私はピーターウェストマコットの回答を2番目に引用します。


私はLa Clojureを使用して成功していましたが、現在筆記体を支持して死にかけているようですgithub.com/JetBrains/la-clojure/blob/master/README.md
leeor

しかし、どのようにしてデバッグにLeiningen、それは示していますError running 'ring server': Trampoline must be enabled for debugging
Gank

それは固有であるように思わringまたはlein別の質問おそらく価値が投稿- ?
dskrvk

6

2016年以降、Debuxを使用できます。これは、replおよびブラウザーのコンソールと連動して機能するClojure / Scriptの単純なデバッグライブラリです。コードに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


5

Hugo Duncanと共同編集者は、ritzプロジェクトで素晴らしい仕事を続けています。Ritz-nreplは、デバッグ機能を備えたnREPLサーバーです。HujuのClojureでデバッガーをClojure / Conj 2012で講演して、実際の動作を確認してください。ビデオで一部のスライドが判読できないため、ここからスライドを表示することをお勧めします。




1

ここだ複雑なデバッグのための素晴らしいマクロ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)))

...そしてその使用法を説明するエッセイ


-4

letを一連のdefに変換するdef-letの関数バージョン。クレジットはここにいく

(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)])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.