Réponses:
Il y a aussi dotrace, qui vous permet de regarder les entrées et sorties des fonctions sélectionnées.
(use 'clojure.contrib.trace)
(defn fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
(dotrace [fib] (fib 3))
produit la sortie:
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
Dans Clojure 1.4, dotrace
a déménagé:
Vous avez besoin de la dépendance:
[org.clojure/tools.trace "0.7.9"]
(require 'clojure.tools.trace)
Et vous devez ajouter le ^: dynamic à la définition de la fonction
(defn ^:dynamic fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
Ensuite, Bob est à nouveau votre oncle:
(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)
J'ai une petite macro de débogage que je trouve très utile:
;;debugging parts of expressions
(defmacro dbg[x] `(let [x# ~x] (println "dbg:" '~x "=" x#) x#))
Vous pouvez l'insérer où vous voulez regarder ce qui se passe et quand:
;; 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
.
Ma méthode préférée est un saupoudrage libéral de println
s partout dans le code ... Les allumer et éteindre est facile grâce à la #_
macro de lecture (qui fait lire le lecteur sous la forme suivante, puis fait semblant de ne jamais l'avoir vu). Ou vous pouvez utiliser une macro se développant sur un corps transmis ou en nil
fonction de la valeur d'une variable spéciale, par exemple *debug*
:
(defmacro debug-do [& body]
(when *debug*
`(do ~@body)))
Avec un (def *debug* false)
là-dedans, cela s'étendra à nil
. Avec true
, il s'agrandira pour body
s'envelopper dans un do
.
La réponse acceptée à cette question SO: Clojure idiomatique pour les rapports d'étape? est très utile lors du débogage des opérations de séquence.
Ensuite , il y a quelque chose qui est actuellement incompatible avec Swank-clojure de » REPL, mais il est trop bon pour ne pas mentionner: debug-repl
. Vous pouvez l'utiliser dans un REPL autonome, ce qui est facile à obtenir par exemple avec Leiningen ( lein repl
); et si vous lancez votre programme à partir de la ligne de commande, alors il va afficher son propre REPL directement dans votre terminal. L'idée est que vous pouvez laisser tomber la debug-repl
macro où vous voulez et avoir apporter son propre REPL lorsque les biefs d'exécution du programme qui points, avec toutes les sections locales de périmètre , etc. Un couple de liens pertinents: Le Clojure debug-repl , debug Clojure -repl astuces , comment faire un débogage-repl (sur le groupe Google Clojure), débogage-repl sur Clojars .
swank-clojure fait un travail adéquat pour rendre le débogueur intégré de SLIME utile lorsque vous travaillez avec du code Clojure - notez comment les bits non pertinents de la trace de pile sont grisés afin qu'il soit facile de trouver le problème réel dans le code en cours de débogage. Une chose à garder à l'esprit est que les fonctions anonymes sans «balises de nom» apparaissent dans la pile de traces sans aucune information utile qui leur est attachée; quand une "étiquette de nom" est ajoutée, elle apparaît dans le stacktrace et tout va bien à nouveau:
(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)
^^^
Vous pouvez également insérer du code pour vous déposer dans un REPL avec toutes les liaisons locales, en utilisant 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))))
Ensuite, pour l'utiliser, insérez-le où vous voulez que la réponse démarre:
(defn my-function [a b c]
(let [d (some-calc)]
(debug-repl)))
Je le colle dans mon user.clj donc il est disponible dans toutes les sessions REPL.
"meilleures façons de déboguer le code Clojure, tout en utilisant la repl"
Champ légèrement à gauche, mais «en utilisant le REPL lui-même».
J'écris à l'amateur Clojure depuis plus d'un an et je n'ai pas ressenti un grand besoin d'outils de débogage. Si vous gardez vos fonctions petites et exécutez chacune avec les entrées attendues au REPL et observez les résultats, il devrait être possible d'avoir une image assez claire du comportement de votre code.
Je trouve qu'un débogueur est le plus utile pour observer STATE dans une application en cours d'exécution. Clojure facilite (et amusant!) L'écriture dans un style fonctionnel avec des structures de données immuables (pas de changement d'état). Cela réduit considérablement le besoin d'un débogueur. Une fois que je sais que tous les composants se comportent comme prévu (en accordant une attention particulière aux types de choses), le comportement à grande échelle est rarement un problème.
Si vous utilisez emacs / slime / swank, essayez ceci au REPL:
(defn factorial [n]
(cond (< n 2) n
(= n 23) (swank.core/break)
:else (* n (factorial (dec n)))))
(factorial 30)
Cela ne vous donne pas une trace complète de la pile comme vous le feriez sous LISP, mais c'est bon pour fouiner.
C'est le beau travail de:
http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml
comme cela a été mentionné dans un commentaire ci-dessus.
Pour IntelliJ, il existe un excellent plugin Clojure appelé Cursive . Entre autres choses, il fournit un REPL que vous pouvez exécuter en mode débogage et parcourir votre code Clojure comme vous le feriez par exemple pour Java.
Je voudrais cependant seconder la réponse de Peter Westmacott dans la mesure où, d'après mon expérience, l'exécution de morceaux de mon code dans le REPL est la plupart du temps une forme suffisante de débogage.
Leiningen
, cela montre:Error running 'ring server': Trampoline must be enabled for debugging
ring
ou lein
peut-être la peine de publier une question distincte?
Depuis 2016, vous pouvez utiliser Debux , une bibliothèque de débogage simple pour Clojure / Script qui fonctionne en conjonction avec votre repl ainsi que la console de votre navigateur. Vous pouvez saupoudrer dbg
(déboguer) ou clog
(console.log) des macros dans votre code et observer facilement les résultats des fonctions individuelles, etc., imprimés sur votre REPL et / ou console.
Du Readme du projet :
Utilisation basique
Ceci est un exemple simple. La macro dbg imprime un formulaire original et imprime la valeur évaluée dans la fenêtre REPL. Ensuite, il renvoie la valeur sans interférer avec l'exécution du code.
Si vous enveloppez le code avec dbg comme ceci,
(* 2 (dbg (+ 10 20))) ; => 60
les éléments suivants seront imprimés dans la fenêtre REPL.
Sortie REPL:
dbg: (+ 10 20) => 30
DBG imbriqué
La macro dbg peut être imbriquée.
(dbg (* 2 (dbg (+ 10 20)))) ; => 60
Sortie REPL:
`dbg: (+ 10 20) => 30`
dbg: (* 2 (dbg (+ 10 20))) => 60
Hugo Duncan et ses collaborateurs continuent de faire un travail incroyable avec le projet Ritz . Ritz-nrepl est un serveur nREPL avec des capacités de débogage. Regardez les débogueurs de Hugo dans Clojure parler à Clojure / Conj 2012 pour le voir en action, dans la vidéo certaines des diapositives ne sont pas lisibles, vous voudrez peut-être voir les diapositives d' ici .
Utilisez spyscope qui implémente une macro de lecture personnalisée afin que votre code de débogage soit également le code de production https://github.com/dgrnbrg/spyscope
Venant de Java et étant familier avec Eclipse, j'aime ce que Counterclockwise (le plugin Eclipse pour le développement de Clojure) a à offrir: http://doc.ccw-ide.org/documentation.html#_debug_clojure_code
Voici une belle macro pour déboguer des let
formulaires compliqués :
(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)))
... et un essai expliquant son utilisation .
Version fonctionnelle de def-let, qui transforme un let en une série de defs. Un peu de crédit va ici
(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)))))
Utilisation: doit citer le contenu avec une citation, par exemple
(def-let '[a 1 b 2 c (atom 0)])