2012-08-01 11 views
7

पाइपलाइनों को देखते हुए तो जैसे एक ->> पाइपलाइन:सशर्त तत्वों >>

(defn my-fn [] 
    (->> (get-data) 
     (do-foo) 
     (do-bar) 
     (do-baz))) 

मैं विभिन्न चरणों सशर्त करना चाहते हैं। if रूप में डालने के लिए ->> मैक्रो प्रयास के रूप में

(defn my-fn [{:keys [foo bar baz]}] 
    (->> (get-data) 
     (if foo (do-foo) identity) 
     (if bar (do-bar) identity) 
     (if baz (do-baz) identity)) 

हालांकि, यह केवल प्रदर्शन के मामले में दुर्भाग्यपूर्ण लग रहा है (होने:

जो मन में आया था इस लेखन के पहले जिस तरह से इस तरह के रूप में था नोप identity कॉल), लेकिन वास्तव में संकलन करने में विफल रहता है।

यह लिखने का उचित, उचित रूप से DRY तरीका क्या होगा?

+0

क्या 'डेटा-डेटा' अनुक्रम लौटाता है जैसा आमतौर पर '- >>' के साथ उपयोग किया जाता है? क्या 'डू-फ़ंक्शन' साइड इफेक्ट्स कॉल करता है, या कुछ ले रहा/वापस कर रहा है? –

+0

ऐसा लगता है कि अगर थ्रेडेड कॉल में किसी भी सराहनीय तरीके से प्रदर्शन को नुकसान पहुंचाएगा –

+0

@AlexTaggart हां, 'get-data' अनुक्रम देता है - संभावित रूप से काफी लंबा, यह प्रभावी रूप से एक आंतरिक लूप बना देता है। 'Do- *' फ़ंक्शन शुद्ध हैं, जिनके दुष्प्रभाव नहीं हैं; शायद मैंने उदाहरण में कोड को खराब तरीके से नामित किया है। –

उत्तर

6

आधुनिक Clojure (कि 1.5 के रूप में, है) की एक किस्म का समर्थन करता है सशर्त थ्रेडिंग के लिए विकल्प।

as-> शायद आपको सबसे अधिक बहुमुखी है, जो फ़ॉर्म के माध्यम से थ्रेड किए जाने वाले "चीज़" को संदर्भित करने के लिए आपको एक नाम देकर है। उदाहरण के लिए:

(as-> 0 n 
    (inc n) 
    (if false 
    (inc n) 
    n)) 
=> 1 

(as-> 0 n 
    (inc n) 
    (if true 
    (inc n) 
    n)) 
=> 2 

यह जब कार्यों कि पैरामीटर सूची में विभिन्न बिंदुओं पर अभिव्यक्ति सूत्रण की आवश्यकता होती है का एक मिश्रण के साथ काम करने के लिए पर्याप्त लचीलापन प्रदान करता है (कि, से स्विच कर रहा है -> के लिए - >> सिंटेक्स)। कोड पठनीयता के हित में बाहरी नामित चर के उपयोग से बचना चाहिए, लेकिन कई बार यह प्रक्रिया को व्यक्त करने का सबसे स्पष्ट और सरल तरीका है।

cond-> भी है, जो जोड़े के सेट के लिए पूछता है: एक परीक्षण और अभिव्यक्ति अगर वह परीक्षण सही साबित होता है। यह cond के समान है लेकिन पहले सच्चे परीक्षण पर नहीं रुकता है।

4

आप होने से संकलन हिस्सा नहीं है, हालांकि तपस्वी हिस्सा ठीक कर सकते हैं (अगर बयान में निर्णय लेने में चलाने के लिए कार्य करते हैं () का एक और सेट के रूप में इसलिए डाल कर:

(defn my-fn [{:keys [foo bar baz]}] 
    (->> (get-data) 
    ((if foo do-foo identity)) 
    ((if bar do-bar identity)) 
    ((if baz do-baz identity))) 

की एक श्रृंखला में विस्तार होगा इस तरह कहता है:

; choose function   and call it  
    ((if foo do-foo identity) args  ) 
    ((if bar do-bar identity) args  ) 
    ((if baz do-baz identity) args  ) 
+0

धन्यवाद!मैं अपने एफएनएस उद्धृत कर रहा था, यानी '((अगर फू 'डू-फू' पहचान) तर्क देता है) '- आपके उदाहरण ने मुझे अपनी समस्या को डीबग करने में मदद की! व्हील को पुनर्निर्मित न करने का सुझाव देने के लिए –

6

यह भी काम करता है:

(defn my-fn [{:keys [foo bar baz]}] 
    (->> (get-data) 
     (#(if foo (do-foo %) %)) 
     (#(if bar (do-bar %) %)) 
     (#(if baz (do-baz %) %)))) 
4

एक अधिक सामान्य रास्ते जाने के लिए अगर आप बात इस तरह की अक्सर जरूरत है:

 
(defn comp-opt [& flag-fns] 
    (->> flag-fns 
    (partition 2) 
    (filter first) 
    (map second) 
    (apply comp))) 

(defn my-fn [{:keys [foo bar baz]}] 
    (map (comp-opt foo do-foo 
       bar do-bar 
       baz do-baz) 
     (get-data))) 
7

आप इन मैक्रो में रुचि हो सकती https://github.com/pallet/thread-expr

+0

+1। :) मैंने आपकी थ्रेड-एक्सप्र लाइब्रेरी का उपयोग किया है और यह सरल, छोटा, सुरुचिपूर्ण है और ठीक काम करता है। – Gert

+0

क्या आप '(कब-> foo do-foo)' का प्रस्ताव दे रहे हैं, या एक अलग उपयोग? –

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