web-dev-qa-db-ja.com

Clojureでデバッグしますか?

Replを使用しながらClojureコードをデバッグする最良の方法は何ですか?

223
Arun R

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
155

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

;;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)
100

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

CIDER debug

63
Amumu

私のお気に入りの方法は、コード全体にprintlnsをリベラルに振りかけることです...オン/オフの切り替えは簡単です#_リーダーマクロのおかげです(これにより、読者は次の形式で読むことができ、見たことがないふりをすることができます)。または、*debug*などの特別な変数の値に応じて、渡された本文またはnilのいずれかに展開するマクロを使用できます。

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

そこに(def *debug* false)があると、これはnilに展開されます。 trueを使用すると、bodyでラップされたdoに展開されます。


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


次に、swank-clojureのREPLと現在互換性のないものがありますが、言うまでもありません:debug-repl。スタンドアロンREPLで使用できます。ライニンゲン(lein repl);コマンドラインからプログラムを起動する場合、独自のREPL=を端末の右上に表示します。アイデアはdebug-replマクロをドロップできるということです。あなたが好きな場所で、プログラムの実行がそのポイントに達すると、スコープ内のすべてのローカルなどで、独自のREPLを表示します。関連するリンクのカップル: The Clojure debug- replClojure debug-repl tricks「debug-replについて」 (Clojure Googleグループ上)、 Clojars上のdebug-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)
                   ^^^
46
Michał Marczyk

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

36
thnetos

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

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

私は1年以上愛好家のClojureを書いてきましたが、デバッグツールに対する大きなニーズは感じていません。関数を小さく保ち、REPLで期待される入力を使用して各関数を実行し、結果を観察すると、コードの動作を非常に明確に把握できるはずです。

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

14

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

私の経験では、REPLでコードの一部を実行するだけで十分なデバッグが可能です。

9
dskrvk

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

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

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

6
Mallory-Erik

ヒューゴダンカンと共同研究者は、 ritz プロジェクトで素晴らしい仕事を続けています。 Ritz-nrepl は、デバッグ機能を備えたnREPLサーバーです。 ClojureのHugoの Debuggers がClojure/Conj 2012で話している様子をご覧ください here からスライドを表示するには。

5
Rodrigo Taboada

こちら 複雑な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)))

...および その使用法を説明するエッセイ

2

デバッグコードも製品コードであるようにカスタムリーダーマクロを実装するspyscopeを使用します https://github.com/dgrnbrg/spyscope

2
myguidingstar

Javaから来て、Eclipseに精通しているので、私はCounterclockwise(Clojure開発用のEclipseプラグイン)が提供するものが好きです: http://doc.ccw-ide.org/ documentation.html#_debug_clojure_code

1
yotsov