क्लोजर में फ़ंक्शन तर्क के लिए डिफ़ॉल्ट मान कैसे बनाएं


127

मैं इसके साथ आता हूं:

(डिग्ड स्ट्रिंग-> पूर्णांक [str & [base]]
  (पूर्णांक / parseInt str (if (nil? Base) 10 बेस))

(स्ट्रिंग-> पूर्णांक "10")
(स्ट्रिंग-> पूर्णांक "एफएफ" 16)

लेकिन ऐसा करने के लिए यह एक बेहतर तरीका होना चाहिए।

जवाबों:


170

एक फ़ंक्शन में कई हस्ताक्षर हो सकते हैं यदि हस्ताक्षर में भिन्नता हो। आप डिफ़ॉल्ट मानों की आपूर्ति करने के लिए इसका उपयोग कर सकते हैं।

(defn string->integer 
  ([s] (string->integer s 10))
  ([s base] (Integer/parseInt s base)))

ध्यान दें कि मानने वाले falseऔर nilगैर-मान वाले दोनों हैं, (if (nil? base) 10 base)को छोटा किया जा सकता है (if base base 10)या आगे भी किया जा सकता है (or base 10)


3
मुझे लगता है कि दूसरी पंक्ति के लिए फ़ंक्शन नाम को दोहराने के बजाय इसका (recur s 10)उपयोग करना बेहतर होगा । इससे भविष्य में फ़ंक्शन का नाम बदलना आसान हो जाएगा। क्या किसी को इन स्थितियों में उपयोग नहीं करने का कोई कारण पता है? recurstring->integerrecur
रोरी ओ'केन

10
ऐसा लग रहा है कि recurकेवल एक ही धमनी पर काम करता है। यदि आपने ऊपर पुनरावृत्ति की कोशिश की है, उदाहरण के लिए:java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
djhaskin987

इसी मुद्दे में भाग गया। क्या यह समझ में आता है कि फंक्शन खुद को कॉल करेगा (यानी (string->integer s 10))?
कर्ट मुलर

155

आप restक्लोजर 1.2 [ रेफ ] के बाद से नक्शे के रूप में तर्कों को भी नष्ट कर सकते हैं । यह आपको नाम देता है और फ़ंक्शन तर्कों के लिए डिफ़ॉल्ट प्रदान करता है:

(defn string->integer [s & {:keys [base] :or {base 10}}]
    (Integer/parseInt s base))

अब आप कॉल कर सकते हैं

(string->integer "11")
=> 11

या

(string->integer "11" :base 8)
=> 9

आप इसे यहां कार्रवाई में देख सकते हैं: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (उदाहरण के लिए)


1
इतना आसान समझने के लिए अगर एक अजगर पृष्ठभूमि से आ रहा है :)
दान

1
स्वीकार किए गए उत्तर की तुलना में यह समझना बहुत आसान है ... क्या यह स्वीकृत "क्लोजुरियन" तरीका है? कृपया इस दस्तावेज़ में जोड़ने पर विचार करें।
दरोगाओं

1
मैंने इसे संबोधित करने में मदद करने के लिए अनौपचारिक शैली मार्गदर्शिका में एक मुद्दा जोड़ा है
दरोगांस

1
यह उत्तर अधिक प्रभावी ढंग से स्वीकार किए गए उत्तर की तुलना में "उचित" तरीके से पकड़ता है, हालांकि दोनों ठीक काम करेंगे। (ज़ाहिर है, लिस्प भाषाओं की एक बड़ी शक्ति यह है कि आमतौर पर एक ही मौलिक काम करने के कई अलग-अलग तरीके हैं)
जॉन्बेकर्स

2
यह मुझे थोड़ा सा खराब लग रहा था और मुझे इसे कुछ समय तक याद रखने में परेशानी हुई, इसलिए मैंने थोड़ा कम वर्बोज़ मैक्रो बनाया
दोपहर

33

यह समाधान मूल समाधान की भावना के करीब है , लेकिन मामूली क्लीनर है

(defn string->integer [str & [base]]
  (Integer/parseInt str (or base 10)))

एक समान पैटर्न जो आसान हो सकता है orके साथ संयुक्त उपयोग करता हैlet

(defn string->integer [str & [base]]
  (let [base (or base 10)]
    (Integer/parseInt str base)))

इस मामले में अधिक क्रिया होने पर, यदि आप अन्य इनपुट मूल्यों पर निर्भर चूक करना चाहते हैं तो यह उपयोगी हो सकता है । उदाहरण के लिए, निम्नलिखित फ़ंक्शन पर विचार करें:

(defn exemplar [a & [b c]]
  (let [b (or b 5)
        c (or c (* 7 b))]
    ;; or whatever yer actual code might be...
    (println a b c)))

(exemplar 3) => 3 5 35

इस दृष्टिकोण को नामांकित तर्कों के साथ काम करने के लिए आसानी से बढ़ाया जा सकता है (जैसा कि एम। गिलियार के समाधान में):

(defn exemplar [a & {:keys [b c]}]
  (let [b (or b 5)
        c (or c (* 7 b))]
    (println a b c)))

या फ्यूजन का और भी अधिक उपयोग करना:

(defn exemplar [a & {:keys [b c] :or {b 5}}]
  (let [c (or c (* 7 b))]
    (println a b c)))

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

मैं क्लोजर नोब हूं इसलिए शायद ओपन लर्नर सही है, लेकिन यह मैथ्यू के ऊपर दिए गए समाधान का एक दिलचस्प विकल्प है। मुझे इस बारे में जानकर खुशी हुई कि आखिरकार मैं इसका इस्तेमाल करने का फैसला करता हूं या नहीं।
ग्लेनपेटर्सन जूल

orसे अलग है :orके बाद से orके अंतर पता नहीं है nilऔर false
जियानगुरु लियान

@XiangruLian क्या आप कह रहे हैं कि उपयोग करते समय: या, यदि आप गलत पास करते हैं, तो यह डिफ़ॉल्ट के बजाय गलत का उपयोग करना जानता होगा? जबकि इसके साथ या यह डिफ़ॉल्ट का उपयोग करेगा जब झूठे और स्वयं झूठे पारित नहीं होंगे?
डिडिएर ए।

8

एक और दृष्टिकोण है जिस पर आप विचार कर सकते हैं: आंशिक कार्य। ये फ़ंक्शन के लिए डिफ़ॉल्ट मान निर्दिष्ट करने के लिए यकीनन अधिक "कार्यात्मक" और अधिक लचीले तरीके हैं।

एक ऐसा फ़ंक्शन (यदि आवश्यक हो) शुरू करें जिसमें पैरामीटर (ओं) हैं जो आप डिफ़ॉल्ट (ओं) को प्रमुख पैरामीटर (ओं) के रूप में प्रदान करना चाहते हैं:

(defn string->integer [base str]
  (Integer/parseInt str base))

ऐसा इसलिए किया जाता है क्योंकि क्लोजर का संस्करण partialआपको फ़ंक्शन डिफ़ॉल्ट में केवल "डिफ़ॉल्ट" मान प्रदान करता है। एक बार पैरामीटर वांछित होने के बाद, आप फ़ंक्शन का उपयोग करके फ़ंक्शन का "डिफ़ॉल्ट" संस्करण बना सकते हैं partial:

(partial string->integer 10)

इस फ़ंक्शन को कॉल करने योग्य बनाने के लिए कई बार आप इसका उपयोग करके इसे var में डाल सकते हैं def:

(def decimal (partial string->integer 10))
(decimal "10")
;10

आप एक "स्थानीय डिफ़ॉल्ट" भी बना सकते हैं let:

(let [hex (partial string->integer 16)]
  (* (hex "FF") (hex "AA")))
;43350

आंशिक समारोह दृष्टिकोण दूसरों पर एक महत्वपूर्ण लाभ है: उपभोक्ता समारोह की अभी भी तय कर सकते हैं क्या डिफ़ॉल्ट मान के बजाय हो जाएगा निर्माता समारोह के समारोह परिभाषा को संशोधित करने की जरूरत के बिना । इसका उदाहरण उस उदाहरण में दिया गया है hexजहाँ मैंने निर्णय लिया है कि डिफ़ॉल्ट फ़ंक्शन decimalवह नहीं है जो मैं चाहता हूँ।

इस दृष्टिकोण का एक और लाभ यह है कि आप डिफ़ॉल्ट फ़ंक्शन को एक अलग नाम (दशमलव, हेक्स, आदि) असाइन कर सकते हैं जो अधिक वर्णनात्मक हो सकता है और / या एक अलग गुंजाइश (संस्करण, स्थानीय) हो सकता है। यदि वांछित है तो आंशिक फ़ंक्शन को कुछ दृष्टिकोणों के साथ मिश्रित किया जा सकता है:

(defn string->integer 
  ([s] (string->integer s 10))
  ([base s] (Integer/parseInt s base)))

(def hex (partial string->integer 16))

(ध्यान दें कि यह ब्रायन के उत्तर से थोड़ा अलग है क्योंकि इस प्रतिक्रिया के शीर्ष पर दिए गए कारणों के लिए मापदंडों का क्रम उलट गया है)


1
यह वह नहीं है जो सवाल पूछ रहा है; हालांकि यह दिलचस्प है।
ज़ाज

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.