बचने के लिए क्लोजर डेवलपर्स के लिए आम प्रोग्रामिंग गलतियाँ [बंद]


92

क्लोजर डेवलपर्स द्वारा की गई कुछ सामान्य गलतियां क्या हैं, और हम उनसे कैसे बच सकते हैं?

उदाहरण के लिए; क्लोजर के लिए नए लोगों को लगता है कि contains?फ़ंक्शन के रूप में ही काम करता है java.util.Collection#contains। हालांकि, contains?केवल उसी तरह काम करेगा जब नक्शे और सेट जैसे अनुक्रमित संग्रह के साथ उपयोग किया जाता है और आप किसी दिए गए कुंजी की तलाश कर रहे हैं:

(contains? {:a 1 :b 2} :b)
;=> true
(contains? {:a 1 :b 2} 2)
;=> false
(contains? #{:a 1 :b 2} :b)
;=> true

जब संख्यात्मक रूप से अनुक्रमित संग्रह (वैक्टर, सरणियों) के साथ उपयोग किया जाता है, contains? केवल यह जांचता है कि दिए गए तत्व अनुक्रमित (शून्य-आधारित) की वैध सीमा के भीतर हैं:

(contains? [1 2 3 4] 4)
;=> false
(contains? [1 2 3 4] 0)
;=> true

यदि एक सूची दी गई है, contains?तो कभी भी वापस नहीं लौटेगी।


4
सिर्फ FYI करें, jlo.util.Collection # की तलाश करने वाले उन क्लोजर देवों के लिए # टाइप कार्यक्षमता शामिल है, clojure.contrib.seq-utils / check देखें? डॉक्स से: उपयोग: (शामिल है? X x)। लौटें तो सच है, जब समतुल्य (= के साथ) x में रैखिक समय के बराबर कुछ होता है।
रॉबर्ट कैंपबेल

11
आप इस तथ्य को याद करने से चूक गए हैं कि वे प्रश्न समुदाय विकी हैं

3
मैं प्यार करता हूँ कि कैसे पर्ल सवाल सिर्फ अन्य सभी के साथ कदम से बाहर होना है :)
ईथर

8
क्लोजर देवों की तलाश में, मैं rcampbell की सलाह का पालन नहीं करने की सलाह दूंगा। seq-utils लंबे समय से पदावनत है और यह कार्य कभी भी शुरू करने के लिए उपयोगी नहीं था। आप क्लोजर के someफ़ंक्शन का उपयोग कर सकते हैं या, अभी तक बेहतर, बस containsखुद का उपयोग कर सकते हैं। क्लोजर संग्रह लागू java.util.Collection(.contains [1 2 3] 2) => true
रेने

जवाबों:


70

शाब्दिक अष्टक

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

java.lang.NumberFormatException: Invalid number: 08

जो मुझे पूरी तरह से चकित कर गया। कारण यह है कि क्लोजर ऑक्टल पूर्णांक मानों को अग्रणी शून्य के साथ अष्टक के रूप में मानता है, और ऑक्टल में संख्या 08 नहीं है।

मुझे यह भी उल्लेख करना चाहिए कि क्लोजर 0x उपसर्ग के माध्यम से पारंपरिक जावा हेक्साडेसिमल मूल्यों का समर्थन करता है । आप "बेस + आर + वैल्यू" नोटेशन का उपयोग करके 2 और 36 के बीच किसी भी आधार का उपयोग कर सकते हैं, जैसे कि 2r101010 या 36r16 जो 42 बेस दस हैं।


एक अनाम फ़ंक्शन शाब्दिक में शाब्दिक वापसी की कोशिश कर रहा है

यह काम:

user> (defn foo [key val]
    {key val})
#'user/foo
user> (foo :a 1)
{:a 1}

इसलिए मुझे विश्वास था कि यह भी काम करेगा:

(#({%1 %2}) :a 1)

लेकिन इसके साथ असफल:

java.lang.IllegalArgumentException: Wrong number of args passed to: PersistentArrayMap

क्योंकि # () रीडर मैक्रो का विस्तार हो जाता है

(fn [%1 %2] ({%1 %2}))  

कोष्ठक में लिपटे मानचित्र शाब्दिक के साथ। चूंकि यह पहला तत्व है, इसलिए इसे एक फ़ंक्शन के रूप में माना जाता है (जो वास्तव में एक शाब्दिक मानचित्र है), लेकिन कोई आवश्यक तर्क (जैसे कि एक कुंजी) प्रदान नहीं किए जाते हैं। सारांश में, अनाम फ़ंक्शन शाब्दिक का विस्तार नहीं करता है

(fn [%1 %2] {%1 %2})  ; notice the lack of parenthesis

और इसलिए आपके पास अनाम फ़ंक्शन के शरीर के रूप में कोई शाब्दिक मूल्य ([]: a, 4,%) नहीं हो सकता है।

टिप्पणियों में दो समाधान दिए गए हैं। ब्रायन कारपर अनुक्रम कार्यान्वयन कंस्ट्रक्टरों का उपयोग करने का सुझाव देते हैं (सरणी-नक्शा, हैश-सेट, वेक्टर) जैसे:

(#(array-map %1 %2) :a 1)

जबकि दान से पता चलता है कि आप बाहरी कोष्ठक को खोलने के लिए पहचान फ़ंक्शन का उपयोग कर सकते हैं :

(#(identity {%1 %2}) :a 1)

ब्रायन का सुझाव वास्तव में मुझे मेरी अगली गलती के लिए लाता है ...


यह सोचकर कि हैश-मैप या सरणी-मानचित्र अपरिवर्तनीय कंक्रीट मानचित्र कार्यान्वयन को निर्धारित करता है

निम्नलिखित को धयान मे रखते हुए:

user> (class (hash-map))
clojure.lang.PersistentArrayMap
user> (class (hash-map :a 1))
clojure.lang.PersistentHashMap
user> (class (assoc (apply array-map (range 2000)) :a :1))
clojure.lang.PersistentHashMap

जब आप आम तौर पर एक क्लोजर मानचित्र के ठोस कार्यान्वयन के बारे में चिंता करने की ज़रूरत नहीं होगी, तो आपको पता होना चाहिए कि फ़ंक्शंस जो एक नक्शा विकसित करते हैं - जैसे कि एशोक या संयोजन - एक PersistentArrayMap ले सकते हैं और एक PersistentHashMap लौटा सकते हैं , जो बड़े मानचित्रों के साथ तेज़ी से कार्य करता है।


प्रारंभिक बाइंडिंग प्रदान करने के लिए लूप के बजाय पुनरावृत्ति बिंदु के रूप में एक फ़ंक्शन का उपयोग करना

जब मैंने शुरुआत की, तो मैंने इस तरह के कई कार्य लिखे:

; Project Euler #3
(defn p3 
  ([] (p3 775147 600851475143 3))
  ([i n times]
    (if (and (divides? i n) (fast-prime? i times)) i
      (recur (dec i) n times))))

जब वास्तव में लूप इस विशेष कार्य के लिए अधिक संक्षिप्त और मुहावरेदार होगा:

; Elapsed time: 387 msecs
(defn p3 [] {:post [(= % 6857)]}
  (loop [i 775147 n 600851475143 times 3]
    (if (and (divides? i n) (fast-prime? i times)) i
      (recur (dec i) n times))))

ध्यान दें कि मैंने खाली तर्क, "डिफ़ॉल्ट निर्माणकर्ता" फ़ंक्शन बॉडी (p3 775147 600851475143 3) को लूप + प्रारंभिक बाध्यकारी के साथ बदल दिया। पुनरावृत्ति होना अब पाश बाइंडिंग (एफ एन मानकों के बजाय) rebinds और (एफ एन के बजाय पाश,) वापस प्रत्यावर्तन बात करने के लिए कूदता है।


"फैंटम" संस्करण को संदर्भित करना

मैं आपके द्वारा खोजे जाने वाले प्रोग्रामिंग के दौरान REPL के उपयोग के प्रकार के बारे में बात कर रहा हूँ - जो कि अनजाने में आपके संदर्भ में है। जब तक आप नाम स्थान (शायद अपने संपादक को बंद करके) को पुनः लोड नहीं करते हैं, तब तक सब कुछ ठीक रहता है और बाद में आपके कोड में संदर्भित अनबाउंड प्रतीकों का एक गुच्छा खोजता है। यह भी अक्सर होता है जब आप रीफैक्टरिंग कर रहे होते हैं, एक var एक नामस्थान से दूसरे में जा रहे हैं।


लूप के लिए अनिवार्य की तरह सूची की समझ का इलाज करना

अनिवार्य रूप से आप एक नियंत्रित लूप का प्रदर्शन करने के बजाय मौजूदा सूचियों के आधार पर एक आलसी सूची बना रहे हैं। क्लोजर का डोज़क वास्तव में अनिवार्य फॉरेक्स लूपिंग कंस्ट्रक्शन के लिए अधिक अनुरूप है।

वे कैसे भिन्न होते हैं, इसका एक उदाहरण है कि वे उन तत्वों को फ़िल्टर करने की क्षमता रखते हैं, जिनका वे मनमाने ढंग से उपयोग करने के बारे में बताते हैं:

user> (for [n '(1 2 3 4) :when (even? n)] n)
(2 4)

user> (for [n '(4 3 2 1) :while (even? n)] n)
(4)

एक और तरीका यह है कि वे अनंत आलसी दृश्यों पर काम कर सकते हैं:

user> (take 5 (for [x (iterate inc 0) :when (> (* x x) 3)] (* 2 x)))
(4 6 8 10 12)

वे एक से अधिक बाध्यकारी अभिव्यक्ति को संभाल सकते हैं, सबसे पहले सही अभिव्यक्ति पर पुनरावृत्ति करते हैं और अपने तरीके से काम करते हैं:

user> (for [x '(1 2 3) y '(\a \b \c)] (str x y))
("1a" "1b" "1c" "2a" "2b" "2c" "3a" "3b" "3c")

वहाँ भी नहीं है को तोड़ने या जारी रखने के लिए समय से पहले ही बाहर निकलने के लिए।


संरचनाओं का अति प्रयोग

मैं एक ओओपीश पृष्ठभूमि से आता हूं इसलिए जब मैंने क्लोजर शुरू किया तो मेरा दिमाग अभी भी वस्तुओं के संदर्भ में सोच रहा था। मैंने खुद को एक संरचना के रूप में सब कुछ मॉडलिंग किया क्योंकि इसके "सदस्यों" का समूहन, हालांकि ढीला था, जिससे मुझे सहज महसूस हुआ। वास्तव में, संरचनाओं को ज्यादातर एक अनुकूलन माना जाना चाहिए; क्लोजर मेमोरी को संरक्षित करने के लिए चाबियाँ और कुछ लुकअप जानकारी साझा करेगा। आप आगे उन्हें परिभाषित करने का अनुकूलन कर सकते accessors कुंजी देखने प्रक्रिया में तेजी लाने के लिए।

कुल मिलाकर आपको प्रदर्शन के अलावा किसी नक्शे पर एक संरचना का उपयोग करने से कुछ भी हासिल नहीं होता है , इसलिए अतिरिक्त जटिलता इसके लायक नहीं हो सकती है।


बिना सोचे समझे BigDecimal कंस्ट्रक्टर का उपयोग करना

मुझे बहुत से बिगडिमल्स की आवश्यकता थी और इस तरह से बदसूरत कोड लिख रहा था:

(let [foo (BigDecimal. "1") bar (BigDecimal. "42.42") baz (BigDecimal. "24.24")]

जब वास्तव में क्लोजर एम को संख्या में जोड़कर बिगडेसिमल शाब्दिक का समर्थन करता है :

(= (BigDecimal. "42.42") 42.42M) ; true

शक्करयुक्त संस्करण का उपयोग करने से ब्लोट का बहुत हिस्सा कट जाता है। टिप्पणी में, twils उल्लेख किया है कि आप भी उपयोग कर सकते हैं bigdec और bigint कार्यों अधिक स्पष्ट हो सकता है, अभी तक संक्षिप्त रहते हैं।


नाम पैकेज के लिए जावा पैकेज नामकरण रूपांतरणों का उपयोग करना

यह वास्तव में प्रति गलती नहीं है, बल्कि ऐसा कुछ है जो मुहावरेदार संरचना और एक विशिष्ट क्लोजर परियोजना के नामकरण के खिलाफ जाता है। मेरी पहली पर्याप्त क्लोजर परियोजना में नाम स्थान की घोषणाएँ थीं - और इसी तरह की फ़ोल्डर संरचनाएँ -

(ns com.14clouds.myapp.repository)

जो मेरे पूर्ण-योग्य फ़ंक्शन संदर्भों को फूला हुआ करता है:

(com.14clouds.myapp.repository/load-by-name "foo")

चीजों को और अधिक जटिल करने के लिए, मैंने एक मानक मावेन निर्देशिका संरचना का उपयोग किया :

|-- src/
|   |-- main/
|   |   |-- java/
|   |   |-- clojure/
|   |   |-- resources/
|   |-- test/
...

जो "मानक" क्लोजर संरचना की तुलना में अधिक जटिल है:

|-- src/
|-- test/
|-- resources/

जो कि खुद लेनिंगेन प्रोजेक्ट्स और क्लोजर का डिफॉल्ट है।


मैप्स कुंजी मिलान के लिए क्लोज़र के बजाय जावा के बराबर () का उपयोग करते हैं

मूल रूप से आईआरसी पर चॉसर द्वारा रिपोर्ट किया गया , यह जावा के बराबरी () के उपयोग से कुछ अनपेक्षित परिणाम हैं:

user> (= (int 1) (long 1))
true
user> ({(int 1) :found} (int 1) :not-found)
:found
user> ({(int 1) :found} (long 1) :not-found)
:not-found

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

यह ध्यान दिया जाना चाहिए कि java.util.Map इंटरफेस के अनुरूप नक्शे के लिए जावा के बराबरी () के बजाय क्लोज़र के = का उपयोग करना आवश्यक है।


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


1
पाठक मैक्रोज़ के सभी का एक सामान्य फ़ंक्शन संस्करण है। आप कर सकते हैं (#(hash-set %1 %2) :a 1)या इस मामले में (hash-set :a 1)
ब्रायन कारपर

2
आप पहचान के साथ अतिरिक्त कोष्ठक को 'हटा' भी सकते हैं: (# (पहचान {% 1% 2}): 1)

1
तुम भी इस्तेमाल कर सकते हैं do: (#(do {%1 %2}) :a 1)
माइकल मार्कीज

@ मिशेल - मुझे यह समाधान उतना पसंद नहीं है, जितना कि पिछले वाले क्योंकि मुझे लगता है कि एक साइड इफेक्ट हो रहा है, जब वास्तव में यहाँ ऐसा नहीं होता है।
रॉबर्ट कैंपबेल

@ rrc7cz: ठीक है, वास्तव में, यहाँ एक अनाम फ़ंक्शन का उपयोग करने की कोई आवश्यकता नहीं है, क्योंकि hash-mapसीधे (जैसे (hash-map :a 1)या (map hash-map keys vals)) का उपयोग करना अधिक पठनीय है और इसका मतलब यह नहीं है कि नामित नाम में कुछ विशेष और जैसा कि अभी तक लागू नहीं किया गया है। जगह ले रहा है (जो उपयोग का #(...)अर्थ है, मुझे लगता है)। वास्तव में, गुमनाम fns पर काबू पाना अपने आप में सोचने का एक गोत्र है। :-) OTOH, मैं कभी do- कभी सुपर-कॉन्टेक्ट अनाम फ़ंक्शंस में उपयोग करता हूं जो साइड-इफ़ेक्ट फ़्री हैं ... यह स्पष्ट है कि वे एक नज़र में हैं। स्वाद की बात है, मुझे लगता है।
मिचेल मार्कीज

42

आलसी seq का मूल्यांकन करने के लिए मजबूर करना

जब तक आप उनसे मूल्यांकन करने के लिए नहीं कहते हैं, तब तक आलसी seq का मूल्यांकन नहीं किया जाता है। आप इसे कुछ प्रिंट करने की उम्मीद कर सकते हैं, लेकिन यह नहीं है।

user=> (defn foo [] (map println [:foo :bar]) nil)
#'user/foo
user=> (foo)
nil

इसका mapमूल्यांकन कभी नहीं किया जाता है, यह चुपचाप त्याग दिया जाता है, क्योंकि यह आलसी है। आप से एक का उपयोग करने के लिए है doseq, dorun, doallदुष्प्रभाव के लिए आलसी दृश्यों के मूल्यांकन के लिए मजबूर करने आदि।

user=> (defn foo [] (doseq [x [:foo :bar]] (println x)) nil)
#'user/foo
user=> (foo)
:foo
:bar
nil
user=> (defn foo [] (dorun (map println [:foo :bar])) nil)
#'user/foo
user=> (foo)
:foo
:bar
nil

mapREPL तरह के नगों का उपयोग करने पर यह काम करता है, लेकिन यह केवल इसलिए काम करता है क्योंकि REPL आलसी सेक् स का मूल्यांकन करता है। यह बग को नोटिस करने के लिए और भी कठिन बना सकता है, क्योंकि आपका कोड REPL में काम करता है और किसी स्रोत फ़ाइल से या किसी फ़ंक्शन के अंदर काम नहीं करता है।

user=> (map println [:foo :bar])
(:foo
:bar
nil nil)

1
+1। यह मुझे थोड़ा, लेकिन एक और अधिक कपटी तरीके से: मैं (map ...)भीतर से मूल्यांकन कर रहा था (binding ...)और सोच रहा था कि नए बाध्यकारी मूल्य क्यों लागू नहीं होते हैं।
एलेक्स बी

20

मैं क्लोजर नोब हूं। अधिक उन्नत उपयोगकर्ताओं को अधिक दिलचस्प समस्याएं हो सकती हैं।

अनंत आलसी दृश्यों को मुद्रित करने की कोशिश कर रहा है।

मुझे पता था कि मैं अपने आलसी दृश्यों के साथ क्या कर रहा था, लेकिन डिबगिंग के उद्देश्यों के लिए मैंने कुछ प्रिंट / प्रॉन / पीआर कॉल्स डाले, अस्थायी रूप से यह भूल गया कि मैं जो प्रिंट कर रहा था वह क्या था। अजीब बात है, मेरा पीसी सब क्यों लटका हुआ है?

क्लोजर को अनिवार्य रूप से प्रोग्राम करने की कोशिश करना।

कई सारे refs या atoms बनाने और कोड लिखने का प्रलोभन है जो लगातार अपने राज्य के साथ टकराता रहता है। यह किया जा सकता है, लेकिन यह एक अच्छा फिट नहीं है। इसमें खराब प्रदर्शन भी हो सकता है, और कई कोर से शायद ही कभी फायदा होता है।

कार्यात्मक रूप से 100% क्लोजर प्रोग्राम करने की कोशिश कर रहा है।

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

जावा में बहुत अधिक करने की कोशिश कर रहा है।

क्योंकि जावा तक पहुंचना इतना आसान है, यह कभी-कभी जावा के आसपास एक स्क्रिप्टिंग भाषा आवरण के रूप में क्लोजर का उपयोग करने के लिए लुभाता है। जावा लाइब्रेरी की कार्यक्षमता का उपयोग करते समय निश्चित रूप से आपको ऐसा करने की आवश्यकता होगी, लेकिन जावा में डेटा संरचनाओं को बनाए रखने या (जैसे कि क्लोजर में अच्छे समकक्ष हैं) जैसे जावा डेटा प्रकारों का उपयोग करने में बहुत कम समझ है।


13

पहले से ही वर्णित बहुत सारी चीजें। मैं सिर्फ एक और जोड़ दूंगा।

अगर यह मूल्य झूठा है, तो क्लोझर जावा बूलियन ऑब्जेक्ट को हमेशा सही मानता है। इसलिए यदि आपके पास एक जावा भूमि फ़ंक्शन है जो एक जावा बूलियन मान लौटाता है, तो सुनिश्चित करें कि आप इसे सीधे (if java-bool "Yes" "No") नहीं बल्कि चेक करते हैं (if (boolean java-bool) "Yes" "No")

मैं clojure.contrib.sql लाइब्रेरी के साथ इस से जल गया जो जावा बूलियन ऑब्जेक्ट्स के रूप में डेटाबेस बूलियन फ़ील्ड लौटाता है।


8
ध्यान दें कि (if java.lang.Boolean/FALSE (println "foo"))फू प्रिंट नहीं करता है। (if (java.lang.Boolean. "false") (println "foo"))हालांकि, (if (boolean (java.lang.Boolean "false")) (println "foo"))नहीं है , जबकि ... वास्तव में काफी भ्रमित!
मिचेल मार्कीज

यह क्लोजर 1.4.0 में अपेक्षित रूप से काम करने लगता है: (assert (=: false (अगर बूलियन / FALSE: सच: गलत)))
Jakub Holý

हाल ही में करते समय मैं भी इससे जल गया (फ़िल्टर: mykey coll) जहाँ: mykey के मान जहाँ Booleans - क्लोज़र-निर्मित संग्रहों के साथ अपेक्षित रूप से काम करता है, लेकिन डीसर्विलाइज्ड संग्रह के साथ नहीं, जब डिफ़ॉल्ट जावा सीरियलाइज़ेशन का उपयोग करके क्रमबद्ध किया जाता है - क्योंकि उन बूलियनों का deserialized है नए बूलियन के रूप में (), और दुख की बात है (नए बूलियन (सच)! = java.lang.Boolean / TRUE)
हेन्डकेगॉन

1
क्लोजर में बूलियन मूल्यों के मूल नियमों को याद रखें - nilऔर falseझूठे हैं, और बाकी सब सच है। एक जावा Booleanनहीं है nilऔर यह नहीं है false(क्योंकि यह एक वस्तु है), इसलिए व्यवहार सुसंगत है।
20

13

अपने सिर को छोरों में रखते हुए।
यदि आप पहले तत्व का संदर्भ रखते हुए संभावित रूप से बहुत बड़े या अनंत, आलसी अनुक्रम के तत्वों पर लूप करते हैं, तो आप मेमोरी से बाहर चलने का जोखिम उठाते हैं।

भूल वहाँ कोई TCO है।
नियमित पूंछ-कॉल स्टैक स्थान का उपभोग करते हैं, और यदि आप सावधान नहीं हैं तो वे अतिप्रवाह करेंगे। Clojure है 'recurऔर 'trampolineऐसे मामलों में जहां अनुकूलित पूंछ कॉल अन्य भाषाओं में इस्तेमाल किया जाएगा के कई को संभालने के लिए है, लेकिन इन तकनीकों जानबूझकर लागू किया जाना है।

काफी-आलसी सीक्वेंस नहीं।
आप के साथ एक आलसी अनुक्रम का निर्माण कर सकते हैं 'lazy-seqया 'lazy-cons(या उच्च स्तर आलसी एपीआई पर निर्माण करके), लेकिन यदि आप इसे में लपेट 'vecया कुछ अन्य समारोह है कि अनुक्रम का एहसास के माध्यम से इसे पारित, तो यह नहीं रह गया है आलसी हो जाएगा। स्टैक और हीप दोनों को इसके द्वारा ओवरफ्लो किया जा सकता है।

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


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

9

loop ... recurजब नक्शे में अनुक्रम अनुक्रम करने के लिए उपयोग करेंगे।

(defn work [data]
    (do-stuff (first data))
    (recur (rest data)))

बनाम

(map do-stuff data)

मैप फ़ंक्शन (नवीनतम शाखा में) chunked दृश्यों और कई अन्य अनुकूलन का उपयोग करता है। इसके अलावा, क्योंकि यह फ़ंक्शन अक्सर चलाया जाता है, हॉटस्पॉट JIT आमतौर पर इसे किसी भी "वार्म अप टाइम" के साथ बाहर जाने के लिए अनुकूलित और तैयार है।


1
ये दो संस्करण वास्तव में समकक्ष नहीं हैं। आपके workकार्य के बराबर है (doseq [item data] (do-stuff item))। (तथ्य के अलावा, काम में वह लूप कभी खत्म नहीं होता है।)
कोटक

हां, पहले वाला अपने तर्कों पर आलस्य को तोड़ता है। परिणामस्वरूप seq में समान मूल्य होंगे हालांकि यह अब आलसी seq नहीं होगा।
आर्थर उल्फेल्ट

+1! मैंने केवल एक और दिन खोजने के लिए कई छोटे पुनरावर्ती कार्य लिखे, जिनका उपयोग mapऔर / या करके इन सभी को सामान्यीकृत किया जा सकता है reduce
nperson325681

5

कुछ कार्यों के लिए संग्रह प्रकार के अलग-अलग व्यवहार हैं:

user=> (conj '(1 2 3) 4)    
(4 1 2 3)                 ;; new element at the front
user=> (conj [1 2 3] 4) 
[1 2 3 4]                 ;; new element at the back

user=> (into '(3 4) (list 5 6 7))
(7 6 5 3 4)
user=> (into [3 4] (list 5 6 7)) 
[3 4 5 6 7]

स्ट्रिंग्स के साथ काम करना भ्रामक हो सकता है (मैं अभी भी उन्हें प्राप्त नहीं करता हूं)। विशेष रूप से, तार वर्णों के अनुक्रम के समान नहीं होते हैं, भले ही अनुक्रम कार्य उन पर काम करते हैं:

user=> (filter #(> (int %) 96) "abcdABCDefghEFGH")
(\a \b \c \d \e \f \g \h)

एक स्ट्रिंग वापस पाने के लिए, आपको करना होगा:

user=> (apply str (filter #(> (int %) 96) "abcdABCDefghEFGH"))
"abcdefgh"

3

बहुत सारे परांठे, विशेष रूप से शून्य जावा विधि कॉल के साथ, जिसके परिणामस्वरूप NPE:

public void foo() {}

((.foo))

बाहरी परिन्थेस से एनपीई में परिणाम क्योंकि आंतरिक परांठे नील का मूल्यांकन करते हैं।

public int bar() { return 5; }

((.bar)) 

डीबग करने के लिए आसान परिणाम:

java.lang.Integer cannot be cast to clojure.lang.IFn
  [Thrown class java.lang.ClassCastException]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.