Quali sono i modi migliori per eseguire il debug del codice Clojure, mentre si utilizza il repl?Debug in Clojure?
risposta
Il mio metodo preferito è una spolverata abbondante di println
tutto finito il codice ... loro Accensione e spegnimento è facile grazie alla macro #_
lettore (che rende il lettore di leggere il seguente modulo, poi finta che sia mai visto). Oppure si potrebbe utilizzare una macro in espansione sia a un passato-in del corpo o nil
a seconda del valore di qualche variabile speciale, dicono *debug*
:
(defmacro debug-do [& body]
(when *debug*
`(do [email protected])))
Con un (def *debug* false)
in là, questo si espanderà a nil
. Con true
, si espanderà a body
avvolto in un do
.
La risposta accettata a questa domanda SO: Idiomatic Clojure for progress reporting? è molto utile durante il debug operazioni di sequenza.
Poi c'è qualcosa che è attualmente incompatibile con REPL Swank-clojure 's, ma è troppo bello per non parlare: debug-repl
. Puoi usarlo in un REPL standalone, che è facile da ottenere ad es. con Leiningen (lein repl
); e se stai lanciando il tuo programma dalla riga di comando, allora porterà il proprio REPL direttamente nel tuo terminale. L'idea è che puoi rilasciare la macro debug-repl
ovunque desideri e farla aprire il REPL proprio quando l'esecuzione del programma raggiunge quel punto, con tutti i locali nello scope ecc. Un paio di link rilevanti: The Clojure debug-repl, Clojure debug-repl tricks, su how 'bout a debug-repl il gruppo Clojure di Google), debug-repl on Clojars.
Swank-clojure fa un lavoro adeguato di rendere debugger integrato di SLIME utile quando si lavora con il codice Clojure - notare come i bit irrilevanti del stacktrace vengono visualizzati in grigio in modo che sia facile trovare il problema reale nella codice in fase di debug. Una cosa da tenere a mente è che le funzioni anonime senza "tag name" appaiono nello stacktrace senza fondamentalmente nessuna informazione utile ad esse connessa; quando viene aggiunto un "tag nome", in quanto sembra nel stacktrace e tutto è di nuovo bene:
(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)
^^^
ho un po 'di macro di debug che trovo molto utile:
;;debugging parts of expressions
(defmacro dbg[x] `(let [x# ~x] (println "dbg:" '~x "=" x#) x#))
È possibile inserire dove si vuole guardare cosa sta succedendo e quando:
;; 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)
C'è anche dotrace, che permette di guardare gli ingressi e le uscite delle funzioni selezionate.
(use 'clojure.contrib.trace)
(defn fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
(dotrace [fib] (fib 3))
produce l'uscita:
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
si è spostato:
È necessario la dipendenza:
[org.clojure/tools.trace "0.7.9"]
(require 'clojure.tools.trace)
ed è necessario aggiungere il ^: dinamico alla definizione di funzione
(defn ^:dynamic fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
Poi Bob è ancora una volta tuo zio:
(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
Nizza, ma come si fa a trovare clojure 'clojure.contrib.trace? Ho il jar clojure-contrib sul mio classpath ma REPL dice 'user => (usa 'closure.contrib.trace) java.io.FileNotFoundException: Impossibile trovare la chiusura/contrib/trace__init.class o closure/contrib/trace. CLJ sul classpath: (NO_SOURCE_FILE: 0) ' – LarsH
Potrebbe essere errore ortografico clojure come la chiusura, o è un errore di battitura nel commento? Puoi caricare altre librerie clojure.contrib? –
A partire da 1.3 questo è stato spostato in clojure.tools.trace (https://github.com/clojure/tools.trace) – George
È anche possibile inserire codice per inserirsi in un REPL con tutto il locale legature, utilizzando Alex Osborne's debug-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))))
Poi Per utilizzarlo, inserire ovunque si desidera che il repl per iniziare:
(defn my-function [a b c]
(let [d (some-calc)]
(debug-repl)))
mi attengo nel mio user.clj modo che sia disponibile in tutte le sessioni REPL.
Se si usa emacs/melma/Swank, quindi provare questo al REPL:
(defn factorial [n]
(cond (< n 2) n
(= n 23) (swank.core/break)
:else (* n (factorial (dec n)))))
(factorial 30)
Non ti dà una traccia stack completo, come si otterrebbe in LISP, ma è buono per frugare in giro.
Questo è il bel lavoro di:
http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml
come è stato detto in un commento sopra.
Here's una bella macro per il debug complessi let
forme:
(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)))
... e an essay explaining its use.
Versione funzione di def-let, che trasforma una let in una serie di errori. Alcuni merito va a here
(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)))))
Usage: ha bisogno di citare il contenuto con una citazione, per esempio
(def-let '[a 1 b 2 c (atom 0)])
Hugo Duncan e collaboratori continuano a fare il lavoro incredibile con il progetto ritz. Ritz-nrepl è un server nREPL con funzionalità di debug. Guarda il video di Hugo Debuggers in Clojure in Clojure/Conj 2012 per vederlo in azione, nel video alcune diapositive non sono leggibili quindi potresti voler visualizzare le diapositive da here.
"modi migliori per il codice di debug Clojure, durante l'utilizzo del repl"
Leggermente sinistra-campo, ma 'con il REPL iteself'.
Scrivo l'hobbista Clojure da oltre un anno e non ho sentito un grande bisogno di strumenti di debug. Se mantieni le tue funzioni ridotte e esegui ciascuna di esse con gli input previsti al REPL e osservi i risultati, dovrebbe essere possibile avere un'immagine chiara di come si sta comportando il tuo codice.
Trovo che un debugger sia più utile per osservare STATE in un'applicazione in esecuzione. Clojure rende facile (e divertente!) Scrivere in uno stile funzionale con strutture di dati immutabili (nessuno stato mutevole). Questo riduce enormemente la necessità di un debugger. Una volta che so che tutti i componenti si comportano come mi aspetto (prestando particolare attenzione ai tipi di cose), il comportamento su larga scala è raramente un problema.
Questo è principalmente vero, ma quando si esegue la ricorsione su più funzioni, ad esempio, non è così facile. – John
Usa spyscope che attuano un macro lettore personalizzato, in modo che il codice di debug è anche il codice di produzione https://github.com/dgrnbrg/spyscope
Venendo da Java e avere familiarità con Eclipse, mi piace quello in senso antiorario (il plugin Eclipse per lo sviluppo Clojure) deve offerta: http://doc.ccw-ide.org/documentation.html#_debug_clojure_code
nessun supporto breakpoint appropriato. Le discussioni sono difficili da uccidere. – CodeFarmer
Il CIDER di Emacs ha un debugger di origine che consente di inserire espressioni per espressione all'interno di un buffer Emacs e persino di iniettare nuovi valori. Puoi leggere tutto su di esso here. Una demo screenshot:
per IntelliJ c'è un ottimo plug-in Clojure chiamato Cursive. Tra le altre cose, fornisce un REPL che puoi eseguire in modalità di debug e scorrere il codice Clojure proprio come faresti per es. Giava.
Vorrei in secondo luogo la risposta di Peter Westmacott in quanto nella mia esperienza l'esecuzione di parti del mio codice nel REPL è quasi sempre una forma di debug sufficiente.
Stavo usando La Clojure con successo, ma sembra che stia morendo a favore di cursive ora https://github.com/JetBrains/la-clojure/blob/master/README.md – leeor
A partire dal 2016 è possibile utilizzare Debux, una semplice libreria di debug per Clojure/Script che funziona in combinazione con il proprio repl e la console del browser. È possibile cospargere i codici dbg
(debug) o clog
(console.log) nel codice e osservare facilmente i risultati delle singole funzioni, ecc., Stampati sul REPL e/o sulla console.
Dal Readme del progetto:
Utilizzo base
Questo è un semplice esempio. La macro dbg stampa un modulo originale e pretty-prints il valore valutato nella finestra REPL. Quindi restituisce il valore senza interferire con l'esecuzione del codice.
Se si avvolge il codice con dbg come questo,
(* 2 (dbg (+ 10 20))) ; => 60
seguito verrà stampata nella finestra REPL.
uscita REPL:
dbg: (+ 10 20) => 30
nidificati DBG
La macro DBG possono essere nidificate.Uscita
(dbg (* 2 (dbg (+ 10 20)))) ; => 60
REPL:
`dbg: (+ 10 20) => 30`
dbg: (* 2 (dbg (+ 10 20))) => 60
- 1. Come si fa il debug di Clojure in NetBeans IDE?
- 2. Clojure Editor scritto in Clojure
- 3. Metodi consigliati per il debug delle funzioni Clojure?
- 4. clojure: aggiunta una traccia di debug ad ogni funzione in un namespace?
- 5. test Clojure in Maven
- 6. Attori in Clojure
- 7. Ritenzione testa in Clojure
- 8. Consumo WSDL in Clojure
- 9. contatore sincronizzato in clojure
- 10. Introspection in Clojure
- 11. Mutating XML in Clojure
- 12. Ricerca XML in Clojure
- 13. Coda immutabile in Clojure
- 14. Eccezioni personalizzate in Clojure?
- 15. L'override 'richiede' in Clojure?
- 16. Cronologia in Clojure REPL
- 17. Documentazione Clojure in Emacs
- 18. Condivisione strutturale in Clojure
- 19. Iterator blocks in Clojure?
- 20. Enorme XML in Clojure
- 21. Come disambiguare in Clojure
- 22. Modelli MVC in Clojure
- 23. Riferimenti deboli in clojure
- 24. Come agganciare in Clojure
- 25. Sostituzione * con \ * in Clojure
- 26. Assoc-if in Clojure
- 27. Paginazione in clojure
- 28. OAuth1 in Clojure
- 29. Ambito dinamico in Clojure?
- 30. = e == in Clojure
In realtà c'è una versione di debug-repl che funziona con Swank ora: http://hugoduncan.org/post/ 2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml (Spoiler alert: è impressionante) – technomancy
destro, ed è bene avere un collegamento qui, grazie! D'accordo sul fantastico. :-) –
Se questo è il tuo stile, potresti gradire la libreria di debux menzionata in una risposta successiva. https://github.com/philoskim/debux –