2012-04-04 13 views
5

मेरे पास dosync और ref-set का उपयोग करके बनाया गया एक चक्रीय ग्राफ है। जब मैं इसे println पर पास करता हूं तो मुझे java.lang.StackOverflowError मिलता है जैसा कि मैं अपेक्षा करता हूं, क्योंकि यह प्रभावी रूप से असीमित-नेस्टेड संरचना को मुद्रित करने का प्रयास कर रहा है।संदर्भ प्रकारों के लिए println व्यवहार को ओवरराइड करने के लिए कैसे करें

मैंने पाया कि यह कुछ है कि [email protected] की तरह लग रहा है और वास्तव में संरचना पार और सब कुछ बाहर मुद्रित करने के लिए कोशिश नहीं करता बनाता है, तो मैं (str my-ref) करते हैं, तो यह तत्काल अर्थ में समस्या का हल है, लेकिन केवल मदद करता है जब मैं कर रहा हूँ मैं स्क्रीन पर क्या प्रिंट कर रहा हूं इसके बारे में बहुत सावधान हूं। मैं (println my-graph) पर कॉल करने में सक्षम होना चाहता हूं, क्या यह ref को कुछ प्रकार के कस्टम टेक्स्ट (संभवत: str शामिल) के रूप में प्रिंट करता है, और अन्य गैर-रेफरी सामान सामान्य रूप से।

वर्तमान में मेरे पास एक कस्टम प्रिंट फ़ंक्शन है जो संरचना के प्रत्येक तत्व को अपने आप प्रिंट करता है और पूरी तरह से ref प्रिंटिंग छोड़ देता है। (यह पता चला है कि [email protected] पर वास्तव में बहुत उपयोगी नहीं है)। यह उपयोग करने के लिए अजीब है और आरईपीएल में सामानों का आकस्मिक निरीक्षण करने में बाधा डालता है और एमएक्स इंस्पेक्टर को सामान देखने से रोकता है जबकि मैं swank.core/break डीबग चीज़ में हूं।

एक विवरण ref वास्तव में defstruct में एक मान है जिसमें कुछ अन्य सामान भी शामिल हैं जिन्हें मैं सामान्य रूप से प्रिंट करने की कोशिश कर रहा हूं।

तो मैं सोच रहा हूं कि मुझे किस मार्ग पर जाना चाहिए। मैं इन विकल्पों में देखें:

  1. बाहर extend-type चित्रा और मेरे defstruct एड संरचना करने के लिए CharSequence प्रोटोकॉल लागू ताकि जब यह एक ref भर आता है यह ठीक से काम करता है। यह अभी भी ref की बात करते समय संरचना के क्षेत्र-दर-क्षेत्र निरीक्षण और एक विशेष मामले की आवश्यकता है, लेकिन कम से कम यह संरचना को समस्या को स्थानीयकृत करता है, न कि संरचना में शामिल किसी भी चीज़ के लिए।
  2. प्रोटोकॉल को ओवरराइड करने के तरीके को चित्रित करें जब यह ref पर आता है। यह और भी स्थानीयकृत व्यवहार की अनुमति देता है और मुझे आरपीएल पर चक्रीय रेफरी देखने की इजाजत देता है, भले ही यह एक संरचना के अंदर न हो। यह मेरा पसंदीदा विकल्प है।
  3. toString के साथ कुछ करने का तरीका बताएं, जो मुझे लगता है कि println पर कुछ स्तर पर मुझे विश्वास है। मैं इस विकल्प के बारे में सबसे अज्ञानी हूँ। अन्य लोगों के बारे में बहुत अनजान है, लेकिन मैं Joy of Clojure पढ़ रहा हूं और अब मैं सभी प्रेरित हूं।

इसी तरह इस समाधान print और pprint और कुछ और है कि सामान्य रूप से barf होगा जब एक चक्रीय रेफरी प्रिंट करने का प्रयास करने के लिए आवेदन करना चाहिए। मुझे किस रणनीति को नियोजित करना चाहिए?

किसी भी इनपुट के लिए बहुत बहुत धन्यवाद।

+1

fyi, '' (str my-ref) 'का आउटपुट लगभग निश्चित रूप से 'java.lang.Object # toString()' 'को कॉल करने का परिणाम है जैसा कि यहां विस्तृत किया गया है: http://docs.oracle। कॉम/जावाज़/7/डॉक्स/एपीआई/जावा/लैंग/ऑब्जेक्ट.html # टूस्ट्रिंग% 28% 2 9 – sw1nn

+0

ध्यान दें कि 'defreruct' को 'defrecord' द्वारा हटा दिया गया है। इसके अतिरिक्त, 'defstruct' वास्तविक प्रकार नहीं बनाता है इसलिए यह प्रोटोकॉल में भाग नहीं ले सकता है। – raek

+0

मुझे एहसास है कि मैं वास्तव में पहले से ही 'defrecord' का उपयोग कर रहा था। निश्चित नहीं है कि मेरी मूल पोस्ट ने 'defstruct' क्यों कहा। – Sonicsmooth

उत्तर

4

आप जो करना चाहते हैं वह एक नया नामस्थान बनाना है और अपने स्वयं के प्रिंट फ़ंक्शंस को परिभाषित करना है जो क्लोजर ऑब्जेक्ट प्रिंट करता है, और क्लोजर के तरीकों के लिए डिफ़ॉल्ट रूप से मॉड्यूल करता है।

विस्तार में:

    एक एनएस जनसंपर्क-str और प्रिंट-विधि को छोड़कर बनाएँ। एक multimethod प्रिंट-विधि बनाएं (clojure.core में बिल्कुल ठीक है) एक डिफ़ॉल्ट विधि बनाएं जो केवल clojure.core/print-method पर प्रतिनिधि है clojure.lang के लिए कोई विधि बनाएं।रेफरी कि रिकर्सिवली सब कुछ

प्रिंट नहीं करता एक बोनस के रूप में, यदि आप clojure 1.4.0 का उपयोग कर रहे हैं, आप टैग शाब्दिक उपयोग कर सकते हैं ताकि उत्पादन में पढ़ने भी संभव है। आपको कस्टम टैग के लिए *data-readers* मानचित्र ओवरराइड करना होगा और एक फ़ंक्शन जो रेफ ऑब्जेक्ट देता है। *data-readers* के लिए बाइंडिंग को कॉल करने के लिए आपको पढ़ने-स्ट्रिंग व्यवहार को ओवरराइड करने की भी आवश्यकता होगी। सिर्फ एक multimethod जो प्रत्येक विशेष के लिए clojure.core/print-method overloads बना सकते हैं -

मैं java.io.File

के लिए
(ns my.print 
    (:refer-clojure :exclude [pr-str read-string print-method])) 

(defmulti print-method (fn [x writer] 
     (class x))) 

(defmethod print-method :default [o ^java.io.Writer w] 
     (clojure.core/print-method o w)) 

(defmethod print-method java.io.File [o ^java.io.Writer w] 
     (.write w "#myprint/file \"") 
     (.write w (str o)) 
     (.write w "\"")) 

(defn pr-str [obj] 
    (let [s (java.io.StringWriter.)] 
    (print-method obj s) 
    (str s))) 

(defonce reader-map 
    (ref {'myprint/file (fn [arg] 
       (java.io.File. arg))})) 

(defmacro defdata-reader [sym args & body] 
    `(dosync 
    (alter reader-map assoc '~sym (fn ~args [email protected])))) 

(defn read-string [s] 
    (binding [*data-readers* @reader-map] 
    (clojure.core/read-string s))) 

अब आप तो (println (my.print/pr-str circular-data-structure))

+0

धन्यवाद, मैं इसे लागू करने में सक्षम था सिवाय इसके कि मुझे "var: \ * डेटा-पाठकों \ * को हल करने में असमर्थ" मिला। टिप्पणी करने के बाद कि मुझे अभी भी एक विशेष समारोह को कॉल करने के साथ छोड़ दिया गया है जब मुझे पता है कि मैं एक परिपत्र संदर्भ मुद्रित कर रहा हूं। मैं उम्मीद कर रहा था कि क्लोजर स्वचालित रूप से '__str__' या '__repr__' कार्यों को ओवरराइड करके पाइथन में आपके संदर्भ को प्रिंट कर सकता है। – Sonicsmooth

+0

'* डेटा-पाठक * 'केवल तभी काम करता है जब आप क्लोजर 1.4.0 का उपयोग करते हैं, अगर यह आपकी मदद करता है तो भी उत्तर स्वीकार करना सुनिश्चित करें। आप संदर्भों के लिए clojure.core/प्रिंट-विधियों को भी परिभाषित कर सकते हैं, लेकिन फिर आप वैश्विक प्रिंट विधि को संशोधित कर रहे हैं, जो आप चाहते हैं या नहीं भी हो सकता है। – bmillare

+0

मुझे लगता है ... मैंने अभी तक 1.4.0 का प्रयास नहीं किया है। इस उत्तर और इस लिंक के बीच: http://groups.google.com/group/clojure/browse_thread/thread/ef2834ec5937baec/1dba8d1753cda39c मैं अपनी समस्या का समाधान करने में सक्षम था। धन्यवाद। – Sonicsmooth

4

मैं अपने समाधान की तरह कॉल कर सकते हैं एक उदाहरण प्रदान की है टाइप करें, और सामान्य कार्य को multimethod के भीतर से कॉल करें। इस मामले में, प्रत्येक multimethod जेनेरिक print-graph-element को कॉल करता है जो जानता है कि संदर्भों के साथ क्या करना है (यह संदर्भित ऑब्जेक्ट के मान को मुद्रित करने की बजाय संदर्भित ऑब्जेक्ट के हैश को प्रिंट करता है)। इस मामले में मुझे लगता है कि प्रिंट-विधि का प्रेषण कार्य केवल (type <thing>) है, इसलिए यह प्रकार पर प्रेषित होता है, और इस तरह मैं multimethod लिख रहा हूं। मुझे वास्तव में कोई दस्तावेज नहीं मिला था कि प्रिंट-विधि प्रेषण कैसे काम करता है, लेकिन यह सुनिश्चित करता है कि इस तरह से व्यवहार करना प्रतीत होता है।

यह समाधान v0 जैसे (जो repl और प्रिंट-विधि में (कर-शिखर) द्वारा cerated था repl से बुलाया जाता है, इस प्रकार मेरी StackOverflow त्रुटि को रोकने, मुझे अभी-अभी वस्तु का नाम टाइप करने के लिए अनुमति देता है।

(defmethod clojure.core/print-method vertex [v writer] 
    (print-graph-element v)) 
(defmethod clojure.core/print-method edge [e writer] 
    (print-graph-element e)) 
1

तुम सिर्फ छोरों के साथ डाटा संरचनाओं मुद्रित करने के लिए, सीमित करने के लिए कितना गहरा प्रिंटर उतरेगा *print-level* सेट करने का प्रयास सक्षम होने के लिए चाहते हैं।

user=> (def a (atom nil)) 
#'user/a 
user=> (set! *print-level* 3) 
3 
user=> (reset! a a) 
#<[email protected]: #<[email protected]: #<[email protected]: #>>> 

वहाँ भी एक *print-length* वर जो उपयोगी हो सकता है जब है आप असीमित लंबाई के साथ डेटा से निपट रहे हैं।

संबंधित मुद्दे