Antworten:
Es gibt auch Dotrace, mit dem Sie die Ein- und Ausgänge ausgewählter Funktionen anzeigen können.
(use 'clojure.contrib.trace)
(defn fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
(dotrace [fib] (fib 3))
erzeugt die Ausgabe:
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
In Clojure 1.4 dotrace
hat sich bewegt:
Sie benötigen die Abhängigkeit:
[org.clojure/tools.trace "0.7.9"]
(require 'clojure.tools.trace)
Und Sie müssen der Funktionsdefinition die Dynamik ^: hinzufügen
(defn ^:dynamic fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
Dann ist Bob wieder dein Onkel:
(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)
Ich habe ein kleines Debugging-Makro, das ich sehr nützlich finde:
;;debugging parts of expressions
(defmacro dbg[x] `(let [x# ~x] (println "dbg:" '~x "=" x#) x#))
Sie können es einfügen, wo immer Sie sehen möchten, was wann passiert:
;; 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
.
Meine Lieblingsmethode ist das großzügige Streuen von println
s über den gesamten Code ... Das Ein- und Ausschalten ist dank des #_
Lesemakros einfach (das den Leser in der folgenden Form lesen lässt und dann so tut, als hätte er es nie gesehen). Oder Sie können ein Makro verwenden, das entweder zu einem übergebenen Text erweitert wird oder nil
vom Wert einer speziellen Variablen abhängt, z. B *debug*
.:
(defmacro debug-do [& body]
(when *debug*
`(do ~@body)))
Mit einem (def *debug* false)
in dort wird dies erweitert nil
. Mit true
wird es erweitert, um body
in ein eingewickelt do
.
Die akzeptierte Antwort auf diese SO-Frage: Idiomatische Clojure für die Fortschrittsberichterstattung? ist sehr hilfreich beim Debuggen von Sequenzoperationen.
Dann gibt es etwas, das derzeit nicht mit der REPL von swank-clojure kompatibel ist , aber zu gut ist, um es nicht zu erwähnen : debug-repl
. Sie können es in einer eigenständigen REPL verwenden, die zB mit Leiningen ( lein repl
) leicht zu bekommen ist ; Wenn Sie Ihr Programm über die Befehlszeile starten, wird eine eigene REPL direkt in Ihrem Terminal angezeigt. Die Idee ist, dass Sie das debug-repl
Makro an einer beliebigen Stelle ablegen und es seine eigene REPL aufrufen lassen können, wenn die Ausführung des Programms diesen Punkt erreicht, mit allen Einheimischen im Geltungsbereich usw. Einige relevante Links: Das Clojure-Debug-Repl , das Clojure-Debug -repl Tricks , wie wäre es mit einer Debug-Repl (in der Clojure Google-Gruppe), Debug-Repl auf Clojars .
swank-clojure macht den integrierten SLIME-Debugger in angemessener Weise nützlich, wenn Sie mit Clojure-Code arbeiten. Beachten Sie, dass die irrelevanten Teile des Stacktraces ausgegraut sind, sodass das eigentliche Problem im zu debuggenden Code leicht zu finden ist. Beachten Sie, dass anonyme Funktionen ohne "Namensschilder" im Stacktrace angezeigt werden, an die im Grunde keine nützlichen Informationen angehängt sind. Wenn ein "Namensschild" hinzugefügt wird, erscheint es im Stacktrace und alles ist wieder in Ordnung:
(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)
^^^
Sie können auch Code einfügen, um sich mit Alex Osbornesdebug-repl
in eine REPL mit allen lokalen Bindungen einzufügen :
(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))))
Fügen Sie es dann an der Stelle ein, an der die Repl beginnen soll, um es zu verwenden:
(defn my-function [a b c]
(let [d (some-calc)]
(debug-repl)))
Ich stecke dies in meine user.clj, damit es in allen REPL-Sitzungen verfügbar ist.
"Beste Möglichkeiten zum Debuggen von Clojure-Code unter Verwendung der Repl"
Etwas linkes Feld, aber 'mit der REPL selbst'.
Ich schreibe seit über einem Jahr den Hobbyisten Clojure und habe kein großes Bedürfnis nach Debugging-Tools verspürt. Wenn Sie Ihre Funktionen klein halten und jede mit den erwarteten Eingaben an der REPL ausführen und die Ergebnisse beobachten, sollte es möglich sein, ein ziemlich klares Bild davon zu erhalten, wie sich Ihr Code verhält.
Ich finde, ein Debugger ist am nützlichsten, um STATE in einer laufenden Anwendung zu beobachten. Clojure macht es einfach (und macht Spaß!), In einem funktionalen Stil mit unveränderlichen Datenstrukturen zu schreiben (kein sich ändernder Zustand). Dies reduziert den Bedarf an einem Debugger massiv. Sobald ich weiß, dass sich alle Komponenten so verhalten, wie ich es erwartet habe (unter besonderer Berücksichtigung der Arten von Dingen), ist das Verhalten in großem Maßstab selten ein Problem.
Wenn Sie Emacs / Slime / Swank verwenden, versuchen Sie dies bei der REPL:
(defn factorial [n]
(cond (< n 2) n
(= n 23) (swank.core/break)
:else (* n (factorial (dec n)))))
(factorial 30)
Es gibt Ihnen keine vollständige Stapelverfolgung, wie Sie sie unter LISP erhalten würden, aber es ist gut zum Stöbern.
Dies ist die gute Arbeit von:
http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml
wie oben in einem Kommentar erwähnt.
Für IntelliJ gibt es ein exzellentes Clojure-Plugin namens Cursive . Unter anderem bietet es eine REPL, die Sie im Debug-Modus ausführen und Ihren Clojure-Code genau wie bei Java durchlaufen können.
Ich würde die Antwort von Peter Westmacott unterstützen, da meiner Erfahrung nach das Ausführen von Teilen meines Codes in der REPL die meiste Zeit eine ausreichende Form des Debuggens ist.
Leiningen
Error running 'ring server': Trampoline must be enabled for debugging
ring
oder lein
- vielleicht lohnt es sich, eine separate Frage zu stellen?
Ab 2016 können Sie Debux verwenden , eine einfache Debugging-Bibliothek für Clojure / Script, die sowohl mit Ihrem Repl als auch mit der Konsole Ihres Browsers zusammenarbeitet. Sie können Makros in Ihren Code streuen dbg
(debuggen) oder clog
(console.log) und auf einfache Weise die Ergebnisse einzelner Funktionen usw. beobachten, die auf Ihrer REPL und / oder Konsole gedruckt sind.
Aus der Readme - Datei des Projekts :
Grundlegende Verwendung
Dies ist ein einfaches Beispiel. Das Makro dbg druckt ein Originalformular und druckt den ausgewerteten Wert im REPL-Fenster hübsch aus. Dann wird der Wert zurückgegeben, ohne die Codeausführung zu beeinträchtigen.
Wenn Sie den Code wie folgt mit dbg umschließen,
(* 2 (dbg (+ 10 20))) ; => 60
Folgendes wird im REPL-Fenster gedruckt.
REPL-Ausgabe:
dbg: (+ 10 20) => 30
Verschachtelte Datenbank
Das dbg-Makro kann verschachtelt werden.
(dbg (* 2 (dbg (+ 10 20)))) ; => 60
REPL-Ausgabe:
`dbg: (+ 10 20) => 30`
dbg: (* 2 (dbg (+ 10 20))) => 60
Hugo Duncan und seine Mitarbeiter leisten weiterhin hervorragende Arbeit mit dem Ritz- Projekt. Ritz-nrepl ist ein nREPL-Server mit Debug-Funktionen. Sehen Sie sich Hugos Debugger in Clojure- Vorträgen auf der Clojure / Conj 2012 an, um sie in Aktion zu sehen. Im Video sind einige der Folien nicht lesbar, daher möchten Sie die Folien möglicherweise von hier aus anzeigen .
Verwenden Sie Spyscope, das ein benutzerdefiniertes Reader-Makro implementiert, sodass Ihr Debug-Code auch Produktionscode https://github.com/dgrnbrg/spyscope ist
Ich komme aus Java und bin mit Eclipse vertraut. Mir gefällt, was Counterclockwise (das Eclipse-Plugin für die Clojure-Entwicklung) zu bieten hat: http://doc.ccw-ide.org/documentation.html#_debug_clojure_code
Hier ist ein schönes Makro zum Debuggen komplizierter let
Formulare:
(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)))
Funktionsversion von def-let, die aus einem let eine Reihe von defs macht. Ein bisschen Kredit geht hierher
(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)))))
Verwendung: Muss den Inhalt mit einem Zitat zitieren, z
(def-let '[a 1 b 2 c (atom 0)])