2010-06-09 11 views
89

मुझे पता है कि cons एक सीईसी देता है और conj संग्रह देता है। मुझे यह भी पता है कि conj आइटम को संग्रह के इष्टतम छोर पर "जोड़ता है" और cons हमेशा आइटम को "जोड़ता है"। यह उदाहरण इन दोनों बिंदुओं को दिखाता है:क्लोजर: विपक्ष (सीईसी) बनाम conj (सूची)

user=> (conj [1 2 3] 4) //returns a collection 
[1 2 3 4] 
user=> (cons 4 [1 2 3]) //returns a seq 
(4 1 2 3) 

वैक्टर, मानचित्र और सेट के लिए इन मतभेदों को मुझे समझ में आता है। हालांकि, सूचियों के लिए वे समान दिखते हैं।

user=> (conj (list 3 2 1) 4) //returns a list 
(4 3 2 1) 
user=> (cons 4 (list 3 2 1)) //returns a seq 
(4 3 2 1) 

वहाँ सूचियों जहां conj बनाम cons अलग व्यवहार दिखा रहे हैं का उपयोग कर किसी भी उदाहरण हैं, या वे वास्तव में परस्पर विनिमय कर रहे? अलग-अलग वाक्यांश, क्या कोई ऐसा उदाहरण है जहां एक सूची और एक सीक का उपयोग समान रूप से नहीं किया जा सकता है?

उत्तर

140

एक अंतर यह है कि conj एक संग्रह में डालने के लिए तर्क के किसी भी संख्या को स्वीकार करता है cons सिर्फ एक लेता है:

(conj '(1 2 3) 4 5 6) 
; => (6 5 4 1 2 3) 

(cons 4 5 6 '(1 2 3)) 
; => IllegalArgumentException due to wrong arity 

एक और अंतर यह वापसी मान की कक्षा में है:

(class (conj '(1 2 3) 4)) 
; => clojure.lang.PersistentList 

(class (cons 4 '(1 2 3)) 
; => clojure.lang.Cons 

ध्यान दें कि ये वास्तव में विनिमय नहीं कर सकते हैं; विशेष रूप से, clojure.lang.Consclojure.lang.Counted लागू नहीं करता है, इसलिए count पर अब एक स्थिर समय ऑपरेशन नहीं है (इस मामले में यह शायद 1 + 3 तक कम हो जाएगा - 1 पहले तत्व पर रैखिक ट्रैवर्सल से आता है, 3 से आता है (next (cons 4 '(1 2 3))PersistentList और इस प्रकार Counted)।

नाम के पीछे इरादा है कि cons (एक seq truct) विपक्ष का मतलब, conj (एक आइटम oin एक संग्रह पर) संयोजक का मतलब है, जबकि, है मुझे विश्वास है,। seqcons द्वारा निर्मित किया जा रहा है, इसके पहले तर्क के रूप में पारित तत्व के साथ शुरू होता है और इसके next/rest के रूप में दूसरी तर्क में seq के आवेदन से उत्पन्न चीज का हिस्सा होता है; जैसा कि ऊपर प्रदर्शित किया गया है, पूरी बात कक्षा clojure.lang.Cons है। इसके विपरीत, conj हमेशा उसी प्रकार के संग्रह को वापस लौटाता है जैसे संग्रह पास हो जाता है। लिस्प दुनिया में,, (मोटे तौर पर, क्योंकि एक PersistentArrayMap एक PersistentHashMap में जैसे ही चालू हो जाएगा के रूप में यह 9 प्रविष्टियों से परे होती है।)


परंपरागत रूप से, cons विपक्ष (एक जोड़ी tructs) तो Clojure रवाना लिस्प परंपरा से cons फ़ंक्शन में एक सीईसी का निर्माण होता है जिसमें पारंपरिक cdr नहीं होता है। cons का सामान्य उपयोग "अर्थात् कई प्रकार के मूल्यों को एक साथ रखने के लिए या कई मूल्यों को एक साथ रखने के लिए" का अर्थ है, वर्तमान में प्रोग्रामिंग भाषाओं और उनके कार्यान्वयन के अध्ययन में सर्वव्यापी है; इसका मतलब यह है कि "विपक्ष से बचने" का उल्लेख किया गया है।

+1

क्या शानदार लेखन है! मैं अनजान था कि एक विपक्ष प्रकार था। बहुत बढ़िया! –

+0

धन्यवाद। सुन कर खुशी हुई। :-) –

+2

संयोग से, एक विशेष मामले के रूप में, '(cons foo nil)' एक सिंगलटन 'पर्सिस्टेंटलिस्ट' (और इसी तरह 'conj' के लिए) देता है। –

9

मेरी समझ यह है कि आप जो कहते हैं वह सत्य है: सूची में conj एक सूची में विपक्ष के बराबर है।

आप कंज को "कहीं डालें" ऑपरेशन के रूप में सोच सकते हैं, और विपक्ष को "सिर पर डालें" ऑपरेशन के रूप में सोच सकते हैं। एक सूची में, यह सिर पर डालने के लिए सबसे तार्किक है, इसलिए इस मामले में conj और विपक्ष बराबर हैं।

8

एक और अंतर यह है कि क्योंकि conj पहले तर्क के रूप में एक दृश्य लेता है, यह alter के साथ अच्छी तरह से खेलता है जब कुछ अनुक्रम करने के लिए एक ref अद्यतन करने है:

(dosync (alter a-sequence-ref conj an-item)) 

यह मूल रूप से एक धागा सुरक्षित तरीके से (conj a-sequence-ref an-item) करता है। यह cons के साथ काम नहीं करेगा। अधिक जानकारी के लिए स्टू हेलोवे द्वारा Programming Clojure में Concurrency पर अध्याय देखें।

1

एक और अंतर सूची का व्यवहार है?

(list? (conj() 1)) ;=> true 
(list? (cons 1())) ; => false 
+4

विपक्ष हमेशा एक अनुक्रम देता है जो conj प्रदान किए गए एक ही प्रकार का देता है –