2009-07-22 11 views
27

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

सबसे पहले, जब मैं cons स्काला में एक सूची में उदाहरण कोड को देखा, मैंने देखा था कि हर उदाहरण हमेशा दाएँ हाथ की ओर पर सूची था: इस पर देखने के बाद भी

println(1 :: List(2, 3, 4)) 
newList = 42 :: originalList 

हालांकि, और फिर से, मैंने इसके बारे में दो बार नहीं सोचा, क्योंकि मुझे नहीं पता था (उस समय) ::List पर एक विधि है। मैंने अभी माना है कि यह एक ऑपरेटर था (फिर से, जावा में ऑपरेटर की भावना में) और उस सहयोगीता से कोई फर्क नहीं पड़ता। तथ्य यह है कि List हमेशा दाईं ओर दिखाई देता है उदाहरण में कोड संयोग से लग रहा था (मैंने सोचा था कि यह शायद "पसंदीदा शैली" था)।

अब मुझे बेहतर पता है: इसे इस तरह लिखा जाना चाहिए क्योंकि :: सही-सहयोगी है।

मेरा प्रश्न है, सही-सहयोगी तरीकों को परिभाषित करने में सक्षम होने का क्या मतलब है?

क्या यह पूरी तरह से सौंदर्य कारणों से है, या वास्तव में कुछ स्थितियों में बाएं-सहयोगीता पर सही-सहयोगीता का कोई लाभ हो सकता है?

मेरी (नौसिखिया) से बात के देखने के, मैं वास्तव में नहीं दिख रहा है कि कैसे

1 :: myList 

से किसी भी बेहतर

myList :: 1 

है, लेकिन है कि स्पष्ट रूप से इस तरह के एक तुच्छ उदाहरण है कि मुझे शक है है यह एक उचित तुलना है।

+0

कुछ उदाहरणों के साथ उन्हें आपके उत्तर में आपकी टिप्पणियां शामिल की गईं। – VonC

+0

जहां तक ​​मैं कह सकता हूं, यह लिस्प उपयोगकर्ताओं को घर पर महसूस करना है, पूरी तरह से :: सूची संलग्न ऑपरेशन की अनुमति देने के लिए। – skaffman

+3

@ स्काफमैन नहीं, यह नहीं है। जवाब पढ़ें। –

उत्तर

34

संक्षिप्त उत्तर यह है कि सही-सहयोगीता प्रोग्रामर प्रकार को वास्तव में क्या करता है इसके अनुरूप बनाते हुए पठनीयता में सुधार कर सकती है।
तो, यदि आप '1 :: 2 :: 3' टाइप करते हैं, तो आपको पूरी तरह से अलग क्रम में सूची प्राप्त करने के बजाय, एक सूची (1, 2, 3) वापस मिलती है।
होगा ऐसा इसलिए है क्योंकि '1 :: 2 :: 3 :: Nil' वास्तव में

List[Int].3.prepend(2).prepend(1) 

scala> 1 :: 2 :: 3:: Nil 
res0: List[Int] = List(1, 2, 3) 

जो दोनों है:

  • अधिक पठनीय
  • अधिक कुशल (ओ (1) prepend के लिए, बनाम एन ओ() के लिए एक प्राक्कल्पित append विधि)

(अनुस्मारक, Programming in Scala पुस्तक से निकालें)
यदि a * b जैसे ऑपरेटर नोटेशन में कोई विधि उपयोग की जाती है, तो विधि को बाएं ऑपरेंड पर a.*(b) में लागू किया जाता है - जब तक कि विधि का नाम कोलन में समाप्त न हो जाए।
यदि विधि का नाम एक कोलन में समाप्त होता है, तो विधि सही ऑपरेंड पर लागू की जाती है।
इसलिए, 1 :: twoThree में, :: विधि twoThree पर लागू की गई है, इस तरह से 0: twoThree.::(1)

सूची के लिए, यह एक संलग्न आपरेशन की भूमिका (सूची जहां वास्तव में यह 1 जो है सूची में prepended है, के बाद '1' '1 2 3' के रूप में संलग्न किया जा रहा है) निभाता है।
कक्षा सूची एक सच्चे परिशिष्ट संचालन की पेशकश नहीं करती है, क्योंकि सूची में शामिल होने में लगने वाला समय सूची के आकार के साथ रैखिक रूप से बढ़ता है, जबकि के साथ आगे बढ़ना :: निरंतर समय लेता है।
myList :: 1 '1' के लिए MyList की संपूर्ण सामग्री पहले जोड़ें करने की कोशिश करेगा, जो MyList को 1 prepending ('1 :: myList' के रूप में)

नोट से अधिक समय होगा: कोई फर्क नहीं पड़ता एक ऑपरेटर संबद्धता है, हालांकि, इसकी ऑपरेटिंग हमेशा बाएं से दाएं का मूल्यांकन किया जाता है। अभी भी पहले मूल्यांकन किया जाता है

{ val x = a; b.:::(x) } 

इस ब्लॉक एक में:
तो अगर ख एक अभिव्यक्ति है कि एक अपरिवर्तनीय मूल्य के लिए सिर्फ एक सरल संदर्भ है, तो एक ::: ख अधिक सटीक निम्नलिखित ब्लॉक के रूप में व्यवहार किया जाता है नहीं है बी, और उसके बाद इस मूल्यांकन का परिणाम बी के :: :: विधि के लिए एक ऑपरेंड के रूप में पारित किया गया है।


क्यों बनाना बिल्कुल बाएं साहचर्य और सही साहचर्य तरीकों के बीच अंतर?

एक सामान्य बाएं साहचर्य आपरेशन की उपस्थिति रखने के लिए अनुमति देता है कि ('1 :: myList') वास्तव में सही अभिव्यक्ति पर आपरेशन लागू करते समय क्योंकि;

  • यह अधिक कुशल है।
  • लेकिन यह एक व्युत्क्रम साहचर्य आदेश के साथ अधिक पठनीय है ('1 :: myList' बनाम 'myList.prepend(1)')

तो जैसा कि आप कहते हैं, "वाक्यात्मक चीनी", के रूप में तक मुझे पता है।
ध्यान दें, foldLeft के मामले में, उदाहरण के लिए, वे gone a little to far ('/:' सही-साहचर्य ऑपरेटर बराबर के साथ)


हो सकता है आपकी टिप्पणियों से कुछ में शामिल करने के लिए, थोड़ा rephrased:

यदि आप 'एपेंड' फ़ंक्शन पर विचार करते हैं, बाएं-सहयोगी, तो आप 'oneTwo append 3 append 4 append 5' लिखेंगे।
हालांकि, अगर यह 3, 4, और 5 को एक दो में जोड़ना था (जिसे आप जिस तरह से लिखा है) मान लेंगे, तो यह ओ (एन) होगा।
'एपेंड' के लिए '::' के साथ ही होगा। लेकिन यह नहीं है। यह "आगे जोड़ते"

इसका मतलब है कि 'a :: b :: Nil' के लिए वास्तव में है के लिए है 'List[].b.prepend(a)'

यदि '::' पहले जोड़ें करने के लिए और अभी तक रहने के बाएं साहचर्य थे, तो जिसके परिणामस्वरूप सूची गलत क्रम में होगा ।
आप इसे सूची (1, 2, 3, 4, 5) वापस करने की उम्मीद करेंगे, लेकिन यह लौटने वाली सूची (5, 4, 3, 1, 2) को समाप्त कर देगा, जो प्रोग्रामर के लिए अप्रत्याशित हो सकता है।
है यही कारण है, क्योंकि तुमने क्या किया, हो गया होता बाएं साहचर्य क्रम में:

(1,2).prepend(3).prepend(4).prepend(5) : (5,4,3,1,2) 

तो, राइट-संबद्धता कोड मैच वापसी मान के वास्तविक आदेश के साथ बनाता है।

+0

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

+1

ठीक है। मुझे लगता है कि मैं समझता हूं कि आप क्या प्राप्त कर रहे हैं।यदि '::' छोड़ा गया था, तो आप 'oneTwo :: 3 :: 4 :: 5 "लिखेंगे। हालांकि, अगर यह 3, 4, और 5 को एक दो में जोड़ना था (जिसे आप रास्ते से मानेंगे यह लिखा गया है), यह ओ (एन) होगा। हालांकि, यदि '::' प्रीपेन्ड करना था, तब तक बाएं-सहयोगी बने रहें, तो परिणामस्वरूप सूची गलत क्रम में होगी। आप इसे वापस लौटने की उम्मीद करेंगे (1, 2 , 3, 4, 5), लेकिन यह लौटने वाली सूची (5, 4, 3, 1, 2) को समाप्त कर देगा, जो प्रोग्रामर के लिए अप्रत्याशित हो सकता है। इसलिए, दाएं-सहयोगीता कोड को वास्तविक क्रम के साथ मेल खाता है रिटर्न वैल्यू –

+0

मैन, इन छोटे टिप्पणी बक्से में मेरा क्या मतलब है, यह समझाना वाकई मुश्किल है;) संक्षिप्त जवाब यह है कि ऐसा लगता है कि सही-सहयोगीता प्रोग्रामर प्रकार को वास्तव में क्या करता है इसके साथ संगत बनाने के द्वारा पठनीयता में सुधार कर सकती है। इसलिए, यदि आप '1 :: 2 :: 3' टाइप करते हैं, तो आपको सूची पूरी तरह से अलग क्रम में वापस लाने की बजाय सूची (1, 2, 3) वापस मिलती है। –

2

सही-सहयोगी तरीकों को परिभाषित करने में सक्षम होने का क्या मतलब है?

मुझे लगता है कि सही-सहयोगी विधि का बिंदु किसी को भाषा का विस्तार करने का मौका देना है, जो आम तौर पर ओवरराइड ऑपरेटर का बिंदु है।

ऑपरेटर अधिभार एक उपयोगी बात है, इसलिए स्कैला ने कहा: प्रतीकों के किसी संयोजन के लिए इसे क्यों नहीं खोलें? इसके बजाय, ऑपरेटरों और तरीकों के बीच भेद क्यों करें? अब, लाइब्रेरी कार्यान्वयन कैसे Int जैसे अंतर्निहित प्रकारों से सहभागिता करता है? सी ++ में, वह वैश्विक दायरे में friend फ़ंक्शन का उपयोग करती। क्या होगा यदि हम ऑपरेटर :: को लागू करने के लिए सभी प्रकार चाहते हैं?

सही-सहयोगीता :: ऑपरेटर को सभी प्रकारों में जोड़ने का एक साफ तरीका प्रदान करती है। बेशक, तकनीकी रूप से :: ऑपरेटर सूची प्रकार का एक तरीका है। लेकिन यह अंतर्निहित Int और अन्य अन्य प्रकारों के लिए एक मेक-विश्वास ऑपरेटर भी है, कम से कम यदि आप अंत में :: Nil को अनदेखा कर सकते हैं।

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

1 :: 2 :: SuperNil 

यह कुछ हद तक दुर्भाग्यपूर्ण है कि सही संबद्धता वर्तमान में केवल अंत में पेट के लिए हार्ड-कोडेड है, लेकिन मुझे लगता है कि यह बनाता है याद रखना काफी आसान है।

3

जब आप सूची फोल्ड ऑपरेशंस कर रहे हों तो दाएं-सहयोगीता और बाएं-सहयोगीता एक महत्वपूर्ण भूमिका निभाती है। उदाहरण के लिए:

def concat[T](xs: List[T], ys: List[T]): List[T] = (xs foldRight ys)(_::_) 

यह पूरी तरह से ठीक काम करता है। लेकिन आप एक ही foldLeft आपरेशन का उपयोग कर

def concat[T](xs: List[T], ys: List[T]): List[T] = (xs foldLeft ys)(_::_) 

प्रदर्शन नहीं कर सकते, क्योंकि :: राइट साहचर्य है।

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