225 votes

Déboguer à Clojure?

Quelles sont les meilleures façons de déboguer le code Clojure, tout en utilisant le repl?

156voto

Il y a aussi dotrace, qui vous permet de regarder les entrées et les 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 été déplacé:

Vous avez besoin de la dépendance:

 [org.clojure/tools.trace "0.7.5"]
(require 'clojure.tools.trace)
 

Et vous devez ajouter le ^: dynamique à la définition de la fonction

 (defn ^:dynamic fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
 

Alors Bob est encore ton 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
 

100voto

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)
 

46voto

Michał Marczyk Points 54179

Mon préféré de la méthode est un libéral pincée de printlns partout dans le code... de les activer et désactiver est facile grâce à l' #_ lecteur macro (ce qui rend le lecteur à lire le formulaire suivant, puis de faire semblant qu'il ne l'a jamais vu). Ou vous pouvez utiliser une macro en expansion, soit à un passé-corps ou de l' nil selon la valeur d'une variable spéciale, disons *debug*:

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

Avec un (def *debug* false) y, ce sera étendue à d' nil. Avec true, il va l'élargir à d' body enveloppé dans un do.


La accepté de répondre à cette DONC, la question: Idiomatiques Clojure pour les rapports sur les progrès réalisés? est très utile lors du débogage de la séquence des opérations.


Ensuite, il y a quelque chose qui est actuellement incompatible avec swank-clojure's REPL, mais c'est trop bon de ne pas oublier: debug-repl. Vous pouvez l'utiliser en autonome REPL, qui est facile à obtenir par exemple avec Leiningen (lein repl); et si vous êtes le lancement de votre programme à partir de la ligne de commande, alors il va apporter ses propres REPL jusqu'à droit de votre terminal. L'idée est que vous pouvez supprimer l' debug-repl macro dans n'importe où vous le souhaitez et ont-il mettre en place son propre REPL lorsque le programme d'exécution atteint ce point, avec tous les habitants dans le champ d'application etc. Un couple de liens pertinents: Le Clojure debug-repl, Clojure debug-repl astuces, comment 'bout un debug-repl (sur la Clojure groupe Google), debug-repl sur Clojars.


swank-clojure fait un travail adéquat de faire de la BAVE du débogueur intégré utile lorsque vous travaillez avec Clojure code -- notez la pertinence de bits de la stacktrace sont grisées, donc il est facile de trouver le problème dans le code en cours de débogage. Une chose à garder à l'esprit est que les fonctions anonymes, sans nom "tags" apparaissent dans la stacktrace avec pratiquement aucune information utile, lorsqu'un "name tag" est ajouté, il n'apparaît pas dans la 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)
                   ^^^

37voto

thnetos Points 833

Vous pouvez également insérer le code pour vous déposer dans un REPL avec toutes les liaisons locales :

Puis pour l’utiliser, insérez-le où vous voulez le repl pour commencer :

Je m’en tiens ceci dans mon user.clj n’est disponible dans toutes les sessions REPL.

15voto

Peter Westmacott Points 205

"la meilleure des façons pour Déboguer Clojure code, tout en utilisant le repl"

Légèrement à gauche-champ, mais "à l'aide de la REPL iteself'.

J'ai écrit amateur Clojure pour plus d'un an et n'ai pas ressenti un grand besoin d'aucun des outils de débogage. Si vous gardez vos fonctions de petites, et d'exécuter chacun s'attend à l'entrée de RÉPLICATION et d'observer les résultats, alors il devrait être possible d'avoir une idée assez claire de la façon dont votre code est de se comporter.

J'ai trouver un débogueur est le plus utile pour l'observation de l'ÉTAT dans une application en cours d'exécution. Clojure le rend facile (et amusant!) pour écrire dans un style fonctionnel avec des données immuables de structures (pas de changement d'état). Réduit massivement la nécessité d'un débogueur. Une fois, je sais que tous les composants se comportent comme j'attends (en accordant une attention particulière aux types de choses), puis à grande échelle, le comportement est rarement un problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X