Jawaban:
Ada juga dotrace, yang memungkinkan Anda untuk melihat input dan output fungsi yang dipilih.
(use 'clojure.contrib.trace)
(defn fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
(dotrace [fib] (fib 3))
menghasilkan output:
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
Di Clojure 1.4, dotrace
telah pindah:
Anda membutuhkan ketergantungan:
[org.clojure/tools.trace "0.7.9"]
(require 'clojure.tools.trace)
Dan Anda perlu menambahkan ^: dinamis ke definisi fungsi
(defn ^:dynamic fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
Kemudian Bob sekali lagi pamanmu:
(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
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)
Saya memiliki makro debugging kecil yang menurut saya sangat berguna:
;;debugging parts of expressions
(defmacro dbg[x] `(let [x# ~x] (println "dbg:" '~x "=" x#) x#))
Anda dapat memasukkannya di mana pun Anda ingin menonton apa yang terjadi dan kapan:
;; 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
.
Metode favorit saya adalah taburan liberal println
di seluruh kode ... Mengaktifkan dan menonaktifkannya mudah berkat #_
makro pembaca (yang membuat pembaca membaca dalam bentuk berikut, lalu berpura-pura tidak pernah melihatnya). Atau Anda bisa menggunakan ekspansi makro baik ke badan yang lewat atau nil
tergantung pada nilai beberapa variabel khusus, katakan *debug*
:
(defmacro debug-do [& body]
(when *debug*
`(do ~@body)))
Dengan (def *debug* false)
di sana, ini akan diperluas ke nil
. Dengan true
, itu akan berkembang menjadi body
terbungkus a do
.
Jawaban yang diterima untuk pertanyaan SO ini: Clojure Idiomatik untuk pelaporan kemajuan? sangat membantu ketika men-debug operasi urutan.
Lalu ada sesuatu yang saat ini tidak sesuai dengan berlagak-clojure 's REPL, tapi terlalu baik untuk tidak menyebutkan: debug-repl
. Anda dapat menggunakannya dalam REPL mandiri, yang mudah didapat misalnya dengan Leiningen ( lein repl
); dan jika Anda meluncurkan program Anda dari baris perintah, maka itu akan membawa REPL sendiri tepat di terminal Anda. Idenya adalah bahwa Anda dapat menjatuhkan debug-repl
makro di mana saja Anda suka dan memunculkan REPL sendiri ketika eksekusi program mencapai titik itu, dengan semua penduduk setempat dalam ruang lingkup dll. Beberapa tautan yang relevan: Clojure debug-repl , Clojure debug trik -repl , bagaimana dengan debug-repl (pada grup Google Clojure), debug-repl pada Clojars .
swank-clojure melakukan pekerjaan yang memadai untuk menjadikan debugger bawaan SLIME bermanfaat saat bekerja dengan kode Clojure - perhatikan bagaimana bit yang tidak relevan dari stacktrace diklik sehingga mudah untuk menemukan masalah sebenarnya dalam kode yang sedang di-debug. Satu hal yang perlu diingat adalah bahwa fungsi anonim tanpa "tag nama" muncul di stacktrace dengan dasarnya tidak ada informasi berguna yang melekat padanya; ketika "tag nama" ditambahkan, itu muncul di stacktrace dan semuanya baik-baik saja:
(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)
^^^
Anda juga dapat memasukkan kode untuk menjatuhkan diri ke REPL dengan semua binding lokal, menggunakan Alex Osbornedebug-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))))
Kemudian untuk menggunakannya, masukkan di mana pun Anda ingin memulai:
(defn my-function [a b c]
(let [d (some-calc)]
(debug-repl)))
Saya menempel ini di user.clj saya sehingga ini tersedia di semua sesi REPL.
"cara terbaik untuk kode Debug Clojure, saat menggunakan repl"
Bidang kiri sedikit, tetapi 'menggunakan REPL itu sendiri'.
Saya telah menulis hobi Clojure selama lebih dari setahun dan belum merasakan kebutuhan yang besar untuk alat debugging. Jika Anda menjaga fungsi Anda kecil, dan menjalankan masing-masing dengan input yang diharapkan di REPL dan mengamati hasilnya maka itu mungkin untuk memiliki gambaran yang cukup jelas tentang bagaimana kode Anda berperilaku.
Saya menemukan debugger paling berguna untuk mengamati STATE dalam aplikasi yang sedang berjalan. Clojure membuatnya mudah (dan menyenangkan!) Untuk menulis dalam gaya fungsional dengan struktur data yang tidak berubah (tidak ada perubahan kondisi). Ini secara besar-besaran mengurangi kebutuhan akan debugger. Setelah saya tahu bahwa semua komponen berperilaku seperti yang saya harapkan (memberikan perhatian khusus pada jenis-jenis hal) maka perilaku skala besar jarang menjadi masalah.
Jika Anda menggunakan emacs / slime / swank, maka coba ini di REPL:
(defn factorial [n]
(cond (< n 2) n
(= n 23) (swank.core/break)
:else (* n (factorial (dec n)))))
(factorial 30)
Itu tidak memberi Anda jejak tumpukan penuh seperti yang Anda dapatkan di bawah LISP, tapi itu bagus untuk mencari-cari.
Ini adalah karya bagus dari:
http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml
seperti yang disebutkan dalam komentar di atas.
Untuk IntelliJ ada plugin Clojure yang sangat baik yang disebut Cursive . Antara lain, ia menyediakan REPL yang dapat Anda jalankan dalam mode debug dan melangkah melalui kode Clojure Anda seperti yang Anda lakukan untuk Java misalnya.
Saya akan menjawab kedua jawaban Peter Westmacott karena dalam pengalaman saya hanya menjalankan potongan kode saya di REPL sebagian besar waktu merupakan bentuk debugging yang cukup.
Leiningen
, ini menunjukkan:Error running 'ring server': Trampoline must be enabled for debugging
ring
atau lein
- mungkin layak posting pertanyaan terpisah?
Pada 2016 Anda dapat menggunakan Debux , pustaka debugging sederhana untuk Clojure / Script yang bekerja bersama dengan repl Anda serta konsol browser Anda. Anda dapat menaburkan dbg
(debug) atau clog
(console.log) makro dalam kode Anda dan dengan mudah mengamati hasil fungsi individu, dll, dicetak ke REPL Anda dan / atau konsol.
Dari Readme proyek :
Penggunaan dasar
Ini adalah contoh sederhana. Makro dbg mencetak bentuk asli dan mencetak nilai yang dievaluasi pada jendela REPL. Kemudian mengembalikan nilai tanpa mengganggu pelaksanaan kode.
Jika Anda membungkus kode dengan dbg seperti ini,
(* 2 (dbg (+ 10 20))) ; => 60
berikut ini akan dicetak di jendela REPL.
Output REPL:
dbg: (+ 10 20) => 30
Dbg bersarang
Makro dbg dapat disarangkan.
(dbg (* 2 (dbg (+ 10 20)))) ; => 60
Output REPL:
`dbg: (+ 10 20) => 30`
dbg: (* 2 (dbg (+ 10 20))) => 60
Hugo Duncan dan kolaborator terus melakukan pekerjaan luar biasa dengan proyek ritz . Ritz-nrepl adalah server nREPL dengan kemampuan debug. Tonton Hugo Debuggers di Clojure berbicara di Clojure / Conj 2012 untuk melihatnya beraksi, dalam video beberapa slide tidak dapat dibaca sehingga Anda mungkin ingin melihat slide dari sini .
Gunakan spyscope yang mengimplementasikan makro pembaca kustom sehingga kode debug Anda juga merupakan kode produksi https://github.com/dgrnbrg/spyscope
Berasal dari Jawa dan terbiasa dengan Eclipse, saya menyukai apa yang berlawanan dengan berlawanan (plugin Eclipse untuk pengembangan Clojure) tawarkan: http://doc.ccw-ide.org/documentation.html#_debug_clojure_code
Berikut ini makro bagus untuk debugging let
formulir yang rumit :
(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)))
... dan esai yang menjelaskan penggunaannya .
Versi fungsi dari def-let, yang mengubah let menjadi serangkaian def. Beberapa kredit masuk ke sini
(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)))))
Penggunaan: Perlu mengutip konten dengan kutipan, misalnya
(def-let '[a 1 b 2 c (atom 0)])