2011-08-30 22 views
9

मेरे पास tail-seq (contrib - now!) के साथ पढ़ने वाली फ़ाइल से आने वाली आलसी स्ट्रीम लाइनें हैं और मैं उन पंक्तियों को एक से अधिक "श्रोता-कार्य" के साथ संसाधित करना चाहता हूं लाइनों में पुनः-सीक-हिट (या अन्य चीजों) के आधार पर कार्रवाई।एक तर्क, कई फ़ंक्शन

(defn info-listener [logstr] 
    (if (re-seq #"INFO" logstr) (println "Got an INFO-statement"))) 

(defn debug-listener [logstr] 
    (if (re-seq #"DEBUG" logstr) (println "Got a DEBUG-statement"))) 

(doseq [line (tail-seq "/var/log/any/java.log")] 
    (do (info-listener logstr) 
     (debug-listener logstr))) 

और यह उम्मीद के रूप में काम करता है:

मैं निम्नलिखित की कोशिश की। हालांकि, कोड में बहुत सारे कोड-डुप्लिकेशन और अन्य पाप हैं, और यह कोड अपडेट करने के लिए उबाऊ है।

एक महत्वपूर्ण कदम है, एक तर्क के लिए कई कार्यों को लागू करने के यानी

(listen-line line '(info-listener debug-listener)) 

इसके बजाय उसका उपयोग की उबाऊ और त्रुटियों की संभावना do-बयान हो रहा है।

मैं निम्नलिखित प्रतीत होता है चालाक दृष्टिकोण की कोशिश की है:

(defn listen-line [logstr listener-collection] 
    (map #(% logstr) listener-collection)) 

लेकिन यह केवल

(nil) (nil) 

वहाँ lazyiness या प्रथम श्रेणी कार्यों मुझे यकीन है कि के लिए काट रहा है प्रस्तुत हुई है, लेकिन मैं कहाँ रखूँ लागू करें?

मैं समस्या के लिए एक मूल रूप से अलग दृष्टिकोण के लिए भी खुला हूं, लेकिन यह शुरू करने के लिए एक बहुत ही आसान तरीका प्रतीत होता है। मैक्रोज़/बहु विधियां अब के लिए ओवरकिल/गलत लगती हैं।

उत्तर

10

कार्यों के एक समूह से बाहर एक भी समारोह बनाना मुख्य कार्य juxt साथ किया जा सकता एक ही तर्क के साथ कॉल किया जाना चाहिए:

 
=>(def juxted-fn (juxt identity str (partial/100))) 
=>(juxted-fn 50) 
[50 "50" 2] 

partial साथ juxt का मेल बहुत उपयोगी हो सकते हैं:

 
(defn listener [re message logstr] 
    (if (re-seq re logstr) (println message))) 
 
(def juxted-listener 
    (apply juxt (map (fn [[re message]] (partial listner re message)) 
    [[#"INFO","Got INFO"], 
     [#"DEBUG", "Got DEBUG"]])) 
 
(doseq [logstr ["INFO statement", "OTHER statement", "DEBUG statement"]] 
    (juxted-listener logstr)) 

+0

यह बहुत ही सुरुचिपूर्ण है और मुझे क्लोजर (जैसे ऊपर दिए गए उत्तर की तरह) में गहरी अंतर्दृष्टि भी दी गई है। धन्यवाद, एलेक्स! – claj

+1

@claj आप बहुत दयालु हैं। यदि आप अमूर्तता का स्तर लेना चाहते हैं तो आप एक छोटा बदलाव करें और श्रोता के लिए दूसरा तर्क स्वयं को लॉगस्ट्र के साथ बुलाए जाने वाले फ़ंक्शन बनें। यह इनपुट मिलान के आधार पर विभिन्न कार्यों को सक्षम बनाता है। उस समय हमने मूल रूप से एक बहुआयामी को फिर से शुरू किया है। प्रथम श्रेणी इकाइयों के रूप में कार्य बहुत शक्तिशाली abstractions सक्षम! –

9

आप

(listen-line line [info-listener debug-listener]) 

को

(listen-line line '(info-listener debug-listener)) 

बदलने के लिए पहले संस्करण में की जरूरत है, listen-line प्रतीकों info-listener और क्योंकि हवाले से के कार्यों के रूप debug-listener खुद को का उपयोग कर समाप्त होता है। प्रतीक clojure.lang.IFn (क्लोजर फ़ंक्शन आमंत्रण के पीछे इंटरफ़ेस) कीवर्ड को लागू करते हैं, यानी वे मानचित्र-जैसे तर्क (वास्तव में clojure.lang.ILookup) में स्वयं को देखते हैं और nil लौटाते हैं, जो किसी मानचित्र पर लागू होते हैं।

यह भी ध्यान दें कि dorun में listen-line के शरीर को लपेटने की आवश्यकता है ताकि यह सुनिश्चित किया जा सके कि वास्तव में इसे निष्पादित किया जाता है (map आलसी अनुक्रम देता है)। अभी तक बेहतर, doseq करने के लिए स्विच:

(defn listen-line [logstr listener-collection] 
    (doseq [listener listener-collection] 
    (listener logstr))) 
+3

बेहतर बेहतर अभी तक, 'juxt करने के लिए स्विच ':' ((juxt श्रोता-संग्रह लागू करें) logstr) ' – amalloy

+0

सूचियों के साथ मेरी गलती को मददगार रूप से साफ़ करने के लिए मीकल धन्यवाद!मुझे लगता है कि जुर्माना मेरे लिए सबसे बेवकूफ समाधान है हालांकि - उपरोक्त अमलॉय और नीचे दिए गए एलेक्स को भी सुझाव के लिए धन्यवाद! – claj

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