2009-06-28 16 views
7

चारों ओर गुगल करने से, मैंने पाया कि while लूप का उपयोग या चर का उपयोग करना निराश है। यदि इनपुट है 10:abcdefghej यह कोलन के बाद 10 तो पढ़ अगले 10 बाइट्स पार्स आउट कर देगा:क्लोजर वैरिएबल और लूपिंग

अब मैं एक बहुत ही सरल एल्गोरिथ्म है कि एक InputStream से पात्रों पढ़ सकते हैं और तदनुसार पार्स जाएगा कार्यान्वित किया।

जिस चीज के साथ मैं खो गया हूं वह यह है कि मैं इसे कैसे दोबारा कर सकता हूं ताकि यह चर पर निर्भर न हो।


(defn decode-string [input-stream indicator] 

    (with-local-vars [length (str (char indicator)) 
      delimiter (.read input-stream) 
      string (str "") 
      counter 0 ] 

    (while (not(= (var-get delimiter) 58)) 
     (var-set length (str (var-get length) (char (var-get delimiter)))) 
     (var-set delimiter (.read input-stream))) 

    (var-set length (new BigInteger (var-get length))) 
    (var-set counter (var-get length)) 

    (while (not(zero? (var-get counter))) 
     (var-set string (str (var-get string) (char (.read input-stream)) )) 
     (var-set counter (dec (var-get counter)))) 
    (var-get string))) 

इसके अलावा, मैं समझता हूँ कि चर घोषित करने के लिए एक ही रास्ता with-local-vars कीवर्ड का उपयोग कर रहा है। यह एक तरह से अव्यावहारिक शुरुआत में एक ब्लॉक में सभी चर को परिभाषित करने के लिए, या मैं कुछ महत्वपूर्ण बिंदु याद आ रही है नहीं है?

उत्तर

10

इस पार्टी के लिए देर से थोड़ा, मुझे लगता है, लेकिन समस्या यह बहुत सरल है, तो आप बस के रूप में स्ट्रिंग का इलाज वर्णों के अनुक्रम और Clojure के अनुक्रम से निपटने पुरातन का उपयोग करें:

(defn read-prefixed-string [stream] 
    (let [s (repeatedly #(char (.read stream))) 
     [before [colon & after]] (split-with (complement #{\:}) s) 
     num-chars (read-string (apply str before))] 
    (apply str (take num-chars after)))) 

user> (let [in (java.io.StringReader. "10:abcdefghij5:klmnopqrstuvwxyz")] 
     (repeatedly 2 #(read-prefixed-string in))) 
("abcdefghij" "klmno") 

सारांश:

  • , पात्रों में से एक आलसी अनुक्रम में बदसूरत, एक ओर effectful इनपुट धारा कन्वर्ट तो हम कर सकते कि prete और यह इस ऑपरेशन के बाकी हिस्सों के लिए सिर्फ एक स्ट्रिंग है। जैसा कि आप देख सकते हैं, परिणाम की गणना करने के लिए आवश्यक से अधिक वर्ण वास्तव में धारा से पढ़े जाते हैं।
  • स्ट्रिंग को दो हिस्सों में विभाजित करें: पहले कॉलन से पहले आधा अक्षर, और दूसरा आधा जो भी बचा है।
  • उपयोग before और after नामित स्थानीय लोगों के लिए उन हिस्सों के लिए बाध्य है, और : को निकाल देते हैं जब तक हम इसे पर हैं एक अप्रयुक्त स्थानीय, descriptiveness के लिए colon नामित करने के लिए यह बाध्यकारी द्वारा, के लिए destructuring।
  • पढ़ें before इसके संख्यात्मक मूल्य प्राप्त करने के लिए
  • after से कि कई पात्रों ले लो, और (apply str)

Svante के जवाब के साथ एक स्ट्रिंग में उन सब को एक साथ मैश कैसे पाश-ish कोड लिखने के लिए का एक उत्कृष्ट उदाहरण है क्लोजर के साथ; मुझे आशा है कि मेरा अंतर्निहित कार्यों को इकट्ठा करने का एक अच्छा उदाहरण है ताकि वे आपको जो चाहिए वह कर सकें। निश्चित रूप से इनमें से दोनों सी समाधान को कुछ भी दिखते हैं लेकिन "बहुत सरल" बनाते हैं!

+0

आपके द्वारा हमेशा ऐसे महान कार्यात्मक उत्तर! +1 – bmillare

+0

स्ट्रिंग के बजाय स्ट्रीम लेने का निर्णय फ़ंक्शन को और अधिक अनुकूल बनाता है। शुरुआत के लिए अध्ययन करने के लिए यह एक महान क्लोजर स्निपेट है। –

3

मैं खुद को क्लोजर सीख रहा हूं, इसलिए इसे गुरु सलाह के रूप में नहीं बल्कि एक साथी छात्र सलाह के रूप में लें।

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

आप स्पष्ट रूप से कर रहे हैं एक बहुत ही कुशल प्रोग्रामर तो यह जानकारी पर एक नज़र डालें और आप उम्मीद है कि कैसे कार्यात्मक डिजाइन ऑब्जेक्ट ओरिएंटेड डिजाइन से अलग है की एक विचार के अधिक मिलना चाहिए।

http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#Sequence_Functions

इसके अलावा, मैं कुछ clojure कोड देख सलाह देते हैं, तो यहां github.com पर होस्ट एक नमूना प्रोग्राम है जो एक clojure स्क्रीनकास्ट-ट्यूटोरियल का हिस्सा बनने के लिए लिखा गया था है।

http://github.com/technomancy/mire/tree/master

स्क्रीनकास्ट-ट्यूटोरियल जो कोड यहां पाया जा सकता के लिए चाहिए था, लेकिन यह मुक्त नहीं है:

http://peepcode.com/products/functional-programming-with-clojure

(मैं किसी भी तरह peepcode.com के साथ संबद्ध नहीं कर रहा हूँ)।

Clojure के लिए शुभकामनाएं!

18

जो आप लिख रहे हैं वह सी कोड है जो लिप-जैसे सिंटैक्स (कोई अपराध इरादा नहीं है)। आप नहीं करते क्या द्वारा एक शैली को परिभाषित करना बहुत परिभाषित है, लेकिन यह बहुत ही उपयोगी है, तो आप नहीं जानते कि नहीं है "ठीक है, तो किसी और कैसे?"

वैसे, मुझे नहीं पता कि indicator क्या करना है।

  1. समस्या के दो भाग हैं: पढ़ने के लिए वर्णों की संख्या मिल जाए, तो कई अक्षर हैं जो पढ़

    यह मैं कैसे इस समस्या दृष्टिकोण होता है। read-count और read-item, बाद पूर्व का उपयोग कर: इसलिए, मैं दो कार्यों लिखेंगे।

     
    (defn read-count [stream] 
        ;; todo 
    ) 
    
    (defn read-item [stream] 
        ;; todo 
    ) 
    
  2. read-item पहले जरूरतों वर्णों को पढ़ने के की संख्या का निर्धारण करने के लिए। इसके लिए, यह सुविधाजनक फ़ंक्शन read-count का उपयोग करता है जिसे हम परिभाषित भी करेंगे।

     
    (defn read-item [stream] 
        (let [count (read-count stream)] 
        ;; todo 
        )) 
    
  3. Clojure में आम तौर पर सबसे अच्छा loop और recur का उपयोग करके नियंत्रित किया लूपिंग है। loop भी let जैसे चर को बांधता है। acc पढ़ने वाले सामानों को जमा करने के लिए है, लेकिन ध्यान दें कि यह जगह में संशोधित नहीं है लेकिन प्रत्येक पुनरावृत्ति को फिर से बाध्य करता है।

     
    (defn read-item [stream] 
        (loop [count (read-count stream) 
         acc ""] 
        ;; todo 
        (recur (dec count)  ; new value for count 
          (str acc c))))) ; new value for acc 
    
  4. अब हम है कि पाश में कुछ करने की जरूरत है: अगले वर्ण पर बाँध c, लेकिन acc लौट जब count 0. (zero? count)(= count 0) रूप में ही है। मैंने if को उन लोगों के लिए अपरिचित लोगों के लिए थोड़ा सा रूप दिया है।

     
    (defn read-item [stream] 
        (loop [count (read-count stream) 
         acc ""] 
        (if (zero? count)     ; condition 
         acc       ; then 
         (let [c (.read stream)]  ; \ 
          (recur (dec count)   ; > else 
           (str acc c)))))))  ;/
    
  5. अब हम सभी की जरूरत है read-count कार्य है। यह एक समान लूप का उपयोग करता है।

     
    (defn read-count [stream] 
        (loop [count 0] 
        (let [c (.read stream)] 
         (if (= c ":") 
          count 
          (recur (+ (* count 10) 
            (Integer/parseInt c))))))) 
    
  6. इसे आरईपीएल, डीबग, रिफैक्टर पर परीक्षण करें। .read वास्तव में वर्णों को वापस करता है? एक पूर्णांक पार्स करने के लिए एक बेहतर तरीका है?

मैं इस परीक्षण नहीं किया है, और मैं थोड़ा किसी भी अनुभव है और न ही Clojure का गहरा ज्ञान नहीं होने के द्वारा बाधा उत्पन्न कर रहा हूँ (मैं आम ज्यादातर लिस्प का उपयोग करें), लेकिन मुझे लगता है कि यह पता चलता है कि कैसे इस तरह की समस्या से संपर्क करना एक "lispy" तरीके में। ध्यान दें कि वे चर घोषित करने या संशोधित करने के बारे में क्यों नहीं सोचते हैं।

+0

यदि मैं आपकी सलाह को सही ढंग से समझता हूं तो मुझे इसे जितना संभव हो सके अलग-अलग कार्यों में लिखने की कोशिश करके समस्या पर हमला करना चाहिए, क्या मैं सही हूं? –

+1

मैं जितना संभव हो उतना नहीं कहूंगा, उतना ही समझदार --- आप पाते हैं कि आप कौन सी अवधारणाओं का नाम दे सकते हैं, फिर उन्हें उस नाम के पीछे encapsulate। हालांकि, यह उपर्युक्त का सिर्फ एक छोटा सा पहलू है। – Svante

6

Idomatic Clojure वास्तव में अनुक्रमों के साथ काम करने के लिए स्वयं को उधार देता है। सी में मैं वैरिएबल के मामले में सोचता हूं या एक चर की स्थिति को कई बार बदलता हूं। क्लोजर में मैं अनुक्रमों के संदर्भ में सोचता हूं। इस मामले में मैं समस्या को अबास्ट्रक्शन की तीन परतों में तोड़ दूंगा:

  • धारा को बाइट्स के अनुक्रम में बदल दें।
  • अक्षरों के अनुक्रम में बाइट्स के अनुक्रम को
  • अक्षरों के क्रम में वर्णों के अनुक्रम का अनुवाद करें। बाइट्स

धारा: वर्ण

(defn bytes-to-chars [bytes] 
    (map char bytes)) 
को

defn byte-seq [rdr] 
    "create a lazy seq of bytes in a file and close the file at the end" 
    (let [result (. rdr read)] 
    (if (= result -1) 
     (do (. rdr close) nil) 
     (lazy-seq (cons result (byte-seq rdr)))))) 

बाइट्स

वर्ण-टू-तार [वर्ण]

(defn chars-to-strings [chars] 
    (let [length-str (take-wile (#{1234567890} %) chars) 
     length (Integer/parseInt length-str) 
     length-of-lengh (inc (count length-str)) 
     str-seq (drop length-of-length chars)] 
     (lazy-seq 
      (cons 
      (take length str-seq) 
      (recur (drop (+ length-of-length length) chars)))))) 

यह lazily तो हर बार मूल्यांकन किया जाता है अगली स्ट्रिंग की आवश्यकता है इसे इनपुट स्ट्रीम और कंस्ट्रर से खींचा जाएगा ucted। उदाहरण के लिए आप नेटवर्क स्ट्रीम पर इसका इस्तेमाल कर सकते हैं उदाहरण के लिए पहले पूरी धारा को बफर करना होगा या इस स्ट्रीम से कोड पढ़ने के बारे में चिंता करने के बारे में चिंता करें कि यह कैसे बनाया गया है।

पुनश्च: im इस समय मेरी आरईपीएल पर नहीं तो कृपया किसी भी मिली त्रुटियाँ :) ठीक करने के लिए संपादित

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

  • कोई संबंधित समस्या नहीं^_^