क्लोजर में डिबगिंग? [बन्द है]


227

उत्तर का उपयोग करते समय, डीबग क्लोजर कोड के सर्वोत्तम तरीके क्या हैं?


नीचे दिए गए उत्तरों के अतिरिक्त में, REPL गाइड में 'डीबगिंग टूल और तकनीक' देखें: clojure.org/guides/repl/…
वैलेंटाइन वेस्लीनेक

जवाबों:


158

डॉट्रेस भी है, जो आपको चयनित कार्यों के इनपुट और आउटपुट को देखने की अनुमति देता है।

(use 'clojure.contrib.trace)
(defn fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
(dotrace [fib] (fib 3))

उत्पादन का उत्पादन:

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

क्लोजर 1.4 में, dotraceस्थानांतरित हो गया है:

आपको निर्भरता की आवश्यकता है:

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

और आपको फ़ंक्शन परिभाषा में ^: डायनेमिक जोड़ने की आवश्यकता है

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

तब बॉब एक ​​बार फिर आपके चाचा हैं:

(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

2
अच्छा है, लेकिन आप 'clojure.contrib.trace' खोजने के लिए क्लोजर कैसे प्राप्त करते हैं? मेरे 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)
क्लाथपथ पर क्लोजर

2
क्या आप क्लोजर के रूप में क्लोजर को मिस कर सकते हैं, या यह टिप्पणी में एक टाइपो है? क्या आप अन्य clojure.contrib पुस्तकालयों को लोड कर सकते हैं?
जॉन लॉरेंस एस्पेन

12
1.3 के रूप में यह clojure.tools.trace ( github.com/clojure/tools.trace ) में स्थानांतरित हो गया है
जॉर्ज

4
यदि आप प्राप्त कर रहे हैं: "गैरकानूनी तौर पर गैर-गतिशील संस्करण को गतिशील रूप से बाँध नहीं सकते" यहाँ देखें: stackoverflow.com/questions/8875353/…
Cornelius

2
क्या यह 1.5 रिलीज में भी काम कर रहा है? मैं क्लोजर कोन्स के साथ क्लोजर सीख रहा हूं, लेकिन अभी तक काम करने के लिए डॉट्रेस नहीं मिल सकता है।
न्हा

100

मेरे पास थोड़ा डीबगिंग मैक्रो है जो मुझे बहुत उपयोगी लगता है:

;;debugging parts of expressions
(defmacro dbg[x] `(let [x# ~x] (println "dbg:" '~x "=" x#) x#))

आप इसे वहां डाल सकते हैं जहाँ आप देखना चाहते हैं कि क्या चल रहा है और कब:

;; 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
ज़ाज़

4
इससे भी बेहतर: स्पाइसस्कोप
ज़ाज़

@Zaz मैं पूरी तरह से सहमत हूँ। Spyscope कमाल है! डिबगर से भी बेहतर शायद। निश्चित रूप से टाइपिंग के लिए।
J Atkin

66

Emacs के CIDER को एक स्रोत डीबगर मिला, जिसे आप Emacs के बफर के अंदर अभिव्यक्ति द्वारा स्टेप कर सकते हैं और यहां तक ​​कि नए मानों को इंजेक्ट कर सकते हैं। आप यहाँ इसके बारे में सब पढ़ सकते हैं । एक डेमो स्क्रीनशॉट:

CIDER डिबग


46

मेरी पसंदीदा विधि printlnकोड पर सभी में से एक उदार छिड़काव है ... उन्हें चालू करना और बंद करना#_ पाठक मैक्रो के लिए आसान है (जो पाठक को निम्नलिखित रूप में पढ़ता है, फिर दिखावा यह कभी नहीं देखा है)। या आप एक मैक्रो का विस्तार करने के लिए या तो पारित शरीर का उपयोग कर सकते हैं या nilकुछ विशेष चर के मूल्य के आधार पर कह सकते हैं *debug*:

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

एक साथ (def *debug* false)वहाँ में, यह करने के लिए विस्तार होगा nil। के साथ true, यह bodyएक में लिपटे करने के लिए विस्तार करेंगे do


इस SO प्रश्न का स्वीकृत उत्तर: प्रगति रिपोर्टिंग के लिए मुहावरेदार क्लोजर? अनुक्रम ऑपरेशन डिबगिंग जब बहुत उपयोगी है।


तो फिर वहाँ जो कुछ है वर्तमान में स्वांक-clojure के साथ असंगत है आरईपीएल, लेकिन बहुत अच्छा उल्लेख करने के लिए नहीं है: debug-repl। आप इसे एक स्टैंडअलोन आरईपीएल में उपयोग कर सकते हैं, जो कि लेनिंगन ( lein repl) के साथ प्राप्त करना आसान है ; और यदि आप अपने प्रोग्राम को कमांड लाइन से लॉन्च कर रहे हैं, तो यह आपके टर्मिनल में अपने ही REPL को लाने जा रहा है। विचार यह है कि आप अपनी debug-replपसंद के अनुसार मैक्रो को ड्रॉप कर सकते हैं और इसे अपने स्वयं के REPL तक ला सकते हैं जब प्रोग्राम का निष्पादन उस बिंदु तक पहुंचता है, सभी स्थानीय लोगों के साथ गुंजाइश आदि में प्रासंगिक लिंक के एक जोड़े: क्लोजर डिबग-उत्तर , क्लोजर डिबग। -प्ले ट्रिक , कैसे 'एक डिबग- रिप्लाई (क्लोजर गूगल ग्रुप पर), क्लोर्ज पर डिबग-रिप्लाई


Swank-clojure एक पर्याप्त काम करता है SLIME के ​​अंतर्निहित डिबगर को क्लोजर कोड के साथ काम करते समय उपयोगी बनाने पर - ध्यान दें कि स्टैकट्रेस के अप्रासंगिक बिट्स को कैसे निकाला जाता है इसलिए कोड डिबग किए जाने में वास्तविक समस्या का पता लगाना आसान है। एक बात का ध्यान रखें कि "नाम टैग" के बिना अनाम फ़ंक्शन स्टैक्ट्रेस में दिखाई देते हैं, जो मूल रूप से उनके साथ जुड़ी कोई उपयोगी जानकारी नहीं है; जब एक "नाम टैग" जोड़ा जाता है, तो यह स्टैकट्रेस में दिखाई देता है और सब फिर से ठीक हो जाता है:

(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)
                   ^^^

5
वास्तव में डिबग-उत्तर का एक संस्करण है जो अब हंस के साथ काम करता है: hugoduncan.org/post/2010/… (स्पोइलर अलर्ट: यह भयानक है)

1
ठीक है, और यहाँ एक लिंक होना अच्छा है, धन्यवाद! भयानक पर सहमत हुए। :-)
मिशैल मार्कीज़

यदि यह आपकी शैली है, तो आपको बाद की प्रतिक्रिया में उल्लिखित डिबक्स लाइब्रेरी पसंद आ सकती है। github.com/philoskim/debux
Mallory-Erik

@ Mallory-Erik धन्यवाद, मैं इसकी जाँच करूँगा!
मिचेल मार्कीज़

37

आप एलेक्स ओस्बोर्न काdebug-repl उपयोग करते हुए सभी स्थानीय बाइंडिंग के साथ खुद को एक 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))))

फिर इसका उपयोग करने के लिए, जहाँ भी आप प्रारंभ करना चाहते हैं, उसे डालें:

(defn my-function [a b c]
  (let [d (some-calc)]
    (debug-repl)))

मैं इसे अपने user.clj में चिपकाता हूँ, इसलिए यह सभी REPL सत्रों में उपलब्ध है।


16

"उत्तर का उपयोग करते समय क्लूज कोड को डीबग करने के सर्वोत्तम तरीके"

थोड़ा-सा बायाँ क्षेत्र, लेकिन 'REPL iteself का उपयोग करते हुए'।

मैं एक वर्ष से अधिक समय से हॉबी क्लोजर लिख रहा हूं और किसी भी डीबगिंग टूल की बहुत आवश्यकता महसूस नहीं हुई है। यदि आप अपने कार्यों को छोटा रखते हैं, और प्रत्येक को REPL पर अपेक्षित इनपुट के साथ चलाते हैं और परिणामों का निरीक्षण करते हैं, तो आपके कोड का व्यवहार कैसा है, इसकी स्पष्ट रूप से स्पष्ट तस्वीर होना संभव है।

मुझे लगता है कि डिबगर एक चल रहे एप्लिकेशन में स्टेट देखने के लिए सबसे उपयोगी है। क्लोजर को अपरिवर्तनीय डेटा संरचनाओं (कोई बदलते राज्य) के साथ एक कार्यात्मक शैली में लिखना आसान (और मजेदार!) बनाता है। यह बड़े पैमाने पर डिबगर की आवश्यकता को कम करता है। एक बार जब मुझे पता है कि सभी घटक व्यवहार करते हैं जैसा कि मैं उम्मीद करता हूं (चीजों के प्रकार पर विशेष ध्यान देना) तो बड़े पैमाने पर व्यवहार शायद ही कभी एक समस्या है।


यह ज्यादातर सच है लेकिन जब आप कई कार्यों में पुनरावृत्ति करते हैं उदाहरण के लिए यह इतना आसान नहीं है।
जॉन

9

यदि आप emacs / slime / swank का उपयोग करते हैं, तो REPL में यह प्रयास करें:

(defn factorial [n]
        (cond (< n 2) n
              (= n 23) (swank.core/break)
              :else (* n (factorial (dec n)))))

(factorial 30)

यह आपको एक पूर्ण स्टैक ट्रेस नहीं देता है जैसे आप LISP के तहत प्राप्त करेंगे, लेकिन यह चारों ओर poking के लिए अच्छा है।

यह ठीक काम है:

http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml

जैसा कि ऊपर एक टिप्पणी में उल्लेख किया गया था।


9

IntelliJ के लिए Cursive नामक एक उत्कृष्ट Clojure प्लगइन है । अन्य बातों के अलावा, यह एक REPL प्रदान करता है जिसे आप डिबग मोड में चला सकते हैं और अपने Clojure कोड के माध्यम से कदम उठा सकते हैं जैसे आप जावा जैसे।

मैं पीटर वेस्टमाकॉट का जवाब दूंगा, हालांकि मेरे अनुभव में आरईपीएल में सिर्फ मेरे कोड के टुकड़े चल रहे हैं, अधिकांश समय डिबगिंग का पर्याप्त रूप है।


मैं सफलता के साथ ला क्लॉजुर का उपयोग कर रहा था, लेकिन लगता है कि यह अब
कथक के

लेकिन कैसे साथ डिबग करना है Leiningen, यह दिखाता है:Error running 'ring server': Trampoline must be enabled for debugging
Gank

यह विशिष्ट प्रतीत होता है - ringया leinशायद एक अलग प्रश्न पोस्ट करने के लायक है?
dskrvk

6

2016 के रूप में आप डीबक्स का उपयोग कर सकते हैं , क्लॉजुर / स्क्रिप्ट के लिए एक सरल डिबगिंग लाइब्रेरी जो आपके उत्तर के साथ-साथ आपके ब्राउज़र के कंसोल के साथ मिलकर काम करती है। आप अपने कोड में dbg(डीबग) या clog(कंसोल.लॉग) मैक्रोज़ को छिड़क सकते हैं और अपने आरईपीएल और / या कंसोल पर मुद्रित व्यक्तिगत कार्यों आदि के परिणामों का आसानी से निरीक्षण कर सकते हैं।

परियोजना की रीडमी से :

मूल उपयोग

यह एक सरल उदाहरण है। मैक्रो dbg एक मूल रूप प्रिंट करता है और REPL विंडो पर मूल्यांकित मान को सुंदर प्रिंट करता है। फिर यह कोड निष्पादन के साथ हस्तक्षेप किए बिना मान लौटाता है।

यदि आप इस तरह से dbg के साथ कोड को लपेटते हैं,

(* 2 (dbg (+ 10 20))) ; => 60

निम्नलिखित को REPL विंडो में प्रिंट किया जाएगा।

REPL उत्पादन:

dbg: (+ 10 20) => 30

नेस्टेड डी.बी.जी.

Dbg मैक्रो को नेस्टेड किया जा सकता है।

(dbg (* 2 (dbg (+ 10 20)))) ; => 60

REPL उत्पादन:

`dbg: (+ 10 20) => 30`  

dbg: (* 2 (dbg (+ 10 20))) => 60


5

ह्यूगो डंकन और सहयोगी रिट्ज परियोजना के साथ अद्भुत काम करना जारी रखते हैं । Ritz-nrepl डिबग क्षमताओं के साथ एक एनआरईपीएल सर्वर है। वीडियो में इसे देखने के लिए क्लूजुर / कॉनज 2012 में क्लोजर में ह्यूगो के डिबगर्स को देखें, वीडियो में कुछ स्लाइड्स पढ़ने योग्य नहीं हैं, इसलिए आप यहां से स्लाइड देखना चाहते हैं



1

जावा से आ रहा है और ग्रहण से परिचित होने के नाते, मुझे पसंद है कि क्या काउंटरक्लॉकवाइज (क्लोजर डेवलपमेंट के लिए ग्रहण प्लगइन) की पेशकश करनी है: http://doc.ccw-ide.org/documentation.html#_debug_cwjure_code


कोई उचित ब्रेकपॉइंट समर्थन नहीं। धागे को मारना कठिन है।
कोडफर्मर

1

यहाँ जटिल letरूपों डिबगिंग के लिए एक अच्छा मैक्रो है:

(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)))

... और इसके उपयोग की व्याख्या करने वाला एक निबंध


-4

डीफ़-लेट का फ़ंक्शन संस्करण, जो लेट्स को डीफ़ की श्रृंखला में बदल देता है। कुछ श्रेय यहां जाता है

(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)))))

उपयोग: सामग्री को उद्धरण के साथ उद्धृत करने की आवश्यकता है, जैसे

(def-let '[a 1 b 2 c (atom 0)])
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.