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
sをリベラルに振りかけることです...オン/オフの切り替えは簡単です#_
リーダーマクロのおかげです(これにより、読者は次の形式で読むことができ、見たことがないふりをすることができます)。または、*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- repl 、 Clojure 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)
^^^
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を使用すると、不変のデータ構造(状態の変化なし)を備えた機能的なスタイルで簡単に(そして楽しく!)書くことができます。これにより、デバッガの必要性が大幅に削減されます。すべてのコンポーネントが期待どおりに動作することがわかったら(特定の種類に注意を払って)、大規模な動作が問題になることはほとんどありません。
IntelliJには、 Cursive という優れたClojureプラグインがあります。とりわけ、これはREPLを提供します。これをデバッグモードで実行し、Javaなどの場合と同じようにClojureコードをステップ実行できます。
私の経験では、REPLでコードの一部を実行するだけで十分なデバッグが可能です。
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
ヒューゴダンカンと共同研究者は、 ritz プロジェクトで素晴らしい仕事を続けています。 Ritz-nrepl は、デバッグ機能を備えたnREPLサーバーです。 ClojureのHugoの Debuggers がClojure/Conj 2012で話している様子をご覧ください here からスライドを表示するには。
こちら 複雑な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)))
...および その使用法を説明するエッセイ 。
デバッグコードも製品コードであるようにカスタムリーダーマクロを実装するspyscopeを使用します https://github.com/dgrnbrg/spyscope
Javaから来て、Eclipseに精通しているので、私はCounterclockwise(Clojure開発用のEclipseプラグイン)が提供するものが好きです: http://doc.ccw-ide.org/ documentation.html#_debug_clojure_code