रॉक सूचीबद्ध करता है
अब तक हास्केल में अनुक्रमिक डेटा के लिए सबसे अनुकूल डेटा संरचना सूची है
data [a] = a:[a] | []
सूचियाँ आपको s (1) कॉन्स और पैटर्न का मेल देती हैं। मानक पुस्तकालय, और कहा कि प्रस्तावना बात के लिए, उपयोगी सूची कार्यों से भरा हुआ है कि ऐसा करना चाहिए अपने कोड कूड़े ( foldr, map, filter)। सूचियाँ लगातार , उर्फ विशुद्ध रूप से कार्यात्मक हैं, जो बहुत अच्छा है। हास्केल सूचियाँ वास्तव में "सूचियाँ" नहीं हैं क्योंकि वे सहवर्ती हैं (अन्य भाषाएं इन धाराओं को कहते हैं) इसलिए चीजें पसंद हैं
ones :: [Integer]
ones = 1:ones
twos = map (+1) ones
tenTwos = take 10 twos
अद्भुत ढंग से काम करें। अनंत डेटा संरचनाएं रॉक।
हास्केल में सूचियाँ अत्याधिक अनिवार्य भाषाओं (जैसे आलस्य के कारण) में एक इंटरफ़ेस प्रदान करती हैं। तो, यह समझ में आता है कि वे व्यापक रूप से उपयोग किए जाते हैं।
दूसरी ओर
सूचियों के साथ पहली समस्या यह है कि उनमें अनुक्रमण करने के लिए (!!)k (k) समय लगता है, जो कष्टप्रद है। इसके अलावा, ऐप्पल धीमा हो सकता है ++, लेकिन हास्केल के आलसी मूल्यांकन मॉडल का मतलब है कि इन्हें पूरी तरह से परिशोधन के रूप में माना जा सकता है, यदि वे बिल्कुल भी होते हैं।
सूचियों के साथ दूसरी समस्या यह है कि उनके पास खराब डेटा इलाका है। जब वास्तविक मेमोरी में ऑब्जेक्ट्स एक-दूसरे के बगल में नहीं रखे जाते हैं तो वास्तविक प्रोसेसर उच्च स्थिरांक पैदा करते हैं। इसलिए, C ++ std::vectorमें किसी भी शुद्ध लिंक्ड लिस्ट डेटा स्ट्रक्चर की तुलना में "स्नोक" (अंत में ऑब्जेक्ट्स डालना) है जो मुझे पता है, हालांकि यह हस्केल की सूचियों की तुलना में इतना कम अनुकूल नहीं है।
सूचियों के साथ तीसरी समस्या यह है कि उनके पास अंतरिक्ष की खराब क्षमता है। अतिरिक्त पॉइंटर्स के बंच आपके स्टोरेज (एक स्थिर कारक द्वारा) को धक्का देते हैं।
अनुक्रम कार्यात्मक हैं
Data.Sequenceआंतरिक रूप से उंगली के पेड़ों पर आधारित है (मुझे पता है, आप यह जानना नहीं चाहते हैं) जिसका अर्थ है कि उनके पास कुछ अच्छे गुण हैं
- विशुद्ध रूप से कार्यात्मक।
Data.Sequenceएक पूरी तरह से निरंतर डेटा संरचना है।
- पेड़ की शुरुआत और अंत में तेजी से प्रवेश। ϴ (1) (परिशोधित) पहला या अंतिम तत्व प्राप्त करने के लिए, या पेड़ों को जोड़ने के लिए। सूची में सबसे तेजी से कर रहे हैं,
Data.Sequenceसबसे अधिक धीमी गति से है।
- ϴ (लॉग एन) अनुक्रम के मध्य तक पहुंच। इसमें नए क्रम बनाने के लिए मान सम्मिलित करना शामिल है
- उच्च गुणवत्ता एपीआई
दूसरी ओर, Data.Sequenceडेटा स्थानीयता समस्या के लिए बहुत कुछ नहीं करता है, और केवल परिमित संग्रह के लिए काम करता है (यह सूचियों से कम आलसी है)
दिल के बेहोश होने के लिए ऐरे नहीं हैं
Arrays सीएस में सबसे महत्वपूर्ण डेटा संरचनाओं में से एक है, लेकिन वे आलसी शुद्ध कार्यात्मक दुनिया के साथ बहुत अच्छी तरह से फिट नहीं हैं। Arrays संग्रह के मध्य में r (1) पहुंच प्रदान करता है और असाधारण रूप से अच्छा डेटा स्थानीयता / निरंतर कारक। लेकिन, चूंकि वे हास्केल में बहुत अच्छी तरह से फिट नहीं हैं, इसलिए वे उपयोग करने के लिए एक दर्द है। वर्तमान मानक पुस्तकालय में वास्तव में विभिन्न प्रकार के विभिन्न प्रकार हैं। इनमें पूरी तरह से निरंतर सरणियाँ, IO मोनाड के लिए परिवर्तनशील सरणियाँ, ST मोनाड के लिए उत्परिवर्ती सरणियाँ और उपरोक्त के अन-बॉक्सिंग संस्करण शामिल हैं। अधिक चेक आउट के लिए हैस्केल विकी
वेक्टर एक "बेहतर" ऐरे है
Data.Vectorपैकेज एक उच्च स्तर और क्लीनर एपीआई में सरणी अच्छाई के सभी प्रदान करता है। जब तक आप वास्तव में नहीं जानते कि आप क्या कर रहे हैं, आपको प्रदर्शन की तरह सरणी की आवश्यकता होने पर इनका उपयोग करना चाहिए। बेशक, कुछ कैवेट अभी भी लागू होते हैं - डेटा संरचनाओं की तरह उत्परिवर्तित सरणी बस शुद्ध आलसी भाषाओं में अच्छा नहीं खेलती हैं। फिर भी, कभी-कभी आप चाहते हैं कि ओ (1) का प्रदर्शन हो, और Data.Vectorयह आपको एक उपयोगी पैकेज में देता है।
आपके पास अन्य विकल्प हैं
यदि आप सूची को अंत में कुशलता से सम्मिलित करने की क्षमता चाहते हैं, तो आप एक अंतर सूची का उपयोग कर सकते हैं । प्रदर्शन को [Char]खराब करने वाली सूचियों का सबसे अच्छा उदाहरण इससे आता है, जिसमें से प्रस्तावना के रूप में उतारा गया है String। Charसूचियाँ दृढ़ हैं, लेकिन सी स्ट्रिंग्स की तुलना में 20 गुना धीमी गति से चलने की प्रवृत्ति है, इसलिए बेझिझक उपयोग करें Data.Textया बहुत तेज़ करें Data.ByteString। मुझे यकीन है कि अन्य अनुक्रम उन्मुख पुस्तकालय हैं जो मैं अभी नहीं सोच रहा हूं।
निष्कर्ष
90 +% उस समय जब मुझे हास्केल सूचियों में अनुक्रमिक संग्रह की आवश्यकता होती है, वे सही डेटा संरचना हैं। सूची पुनरावृत्तियों की तरह हैं, जो कार्य सूचियों का उपभोग करते हैं वे आसानी से इनमें से किसी भी अन्य डेटा संरचनाओं के साथ उपयोग किए जा सकते हैं, जिनके साथ toListवे आते हैं। एक बेहतर दुनिया में प्रस्तावना पूरी तरह से पैरामीट्रिक होगी कि वह किस प्रकार के कंटेनर का उपयोग करता है, लेकिन वर्तमान []में मानक पुस्तकालय का उपयोग करता है । तो, सूचियों का उपयोग करना (लगभग) हर जहाँ निश्चित रूप से ठीक है।
आप सूची के अधिकांश कार्यों के पूरी तरह से पैरामीट्रिक संस्करण प्राप्त कर सकते हैं (और उनका उपयोग करने के लिए महान हैं)
Prelude.map ---> Prelude.fmap (works for every Functor)
Prelude.foldr/foldl/etc ---> Data.Foldable.foldr/foldl/etc
Prelude.sequence ---> Data.Traversable.sequence
etc
वास्तव में, Data.Traversableएक एपीआई को परिभाषित करता है जो किसी भी चीज की तरह कम या ज्यादा सार्वभौमिक है "जैसे सूची"।
फिर भी, हालांकि आप अच्छे हो सकते हैं और केवल पूरी तरह से पैरामीट्रिक कोड लिख सकते हैं, हम में से अधिकांश नहीं हैं और सभी जगह सूची का उपयोग करते हैं। यदि आप सीख रहे हैं, तो मेरा सुझाव है कि आप भी ऐसा करें।
संपादित करें: टिप्पणियों के आधार पर मुझे लगता है कि मैंने कभी नहीं समझाया कि कब Data.Vectorबनाम का उपयोग किया जाए Data.Sequence। ऐरे और वैक्टर बेहद तेजी से अनुक्रमण और टुकड़ा करने की क्रिया प्रदान करते हैं, लेकिन मौलिक रूप से क्षणिक (अनिवार्य) डेटा संरचनाएं हैं। शुद्ध कार्यात्मक डेटा संरचनाएँ जैसे Data.Sequenceऔर पुराने मानों से []कुशलतापूर्वक नए मान उत्पन्न करती हैं जैसे कि आपने पुराने मूल्यों को संशोधित किया था।
newList oldList = 7 : drop 5 oldList
पुरानी सूची को संशोधित नहीं करता है, और इसे कॉपी करने की आवश्यकता नहीं है। तो भले ही oldListअविश्वसनीय रूप से लंबा हो, यह "संशोधन" बहुत तेज़ होगा। उसी प्रकार
newSequence newValue oldSequence = Sequence.update 3000 newValue oldSequence
newValueअपने 3000 तत्व के स्थान पर एक नए अनुक्रम का निर्माण करेगा । फिर से, यह पुराने अनुक्रम को नष्ट नहीं करता है, यह सिर्फ एक नया बनाता है। लेकिन, यह बहुत कुशलता से करता है, ओ (लॉग (मिनट (के, घुटने)) जहां n अनुक्रम की लंबाई है, और कश्मीर आप को संशोधित करते हैं।
आप आसानी से Vectorsऔर के साथ ऐसा नहीं कर सकते Arrays। उन्हें संशोधित किया जा सकता है लेकिन यह वास्तविक अनिवार्य संशोधन है, और इसलिए नियमित हास्केल कोड में ऐसा नहीं किया जा सकता है। इसका मतलब है Vectorकि पैकेज में संचालन जो संशोधन करना चाहते हैं snocऔर consपूरे वेक्टर को कॉपी करना है ताकि O(n)समय लग सके। इसका एकमात्र अपवाद यह है कि आप मोनड (या ) के Vector.Mutableअंदर उत्परिवर्तित संस्करण ( ) का उपयोग कर सकते हैं और अपने सभी संशोधनों को उसी तरह कर सकते हैं जैसे आप एक अनिवार्य भाषा में करेंगे। जब आप कर लेते हैं, तो आप अपने वेक्टर को उन अपरिवर्तनीय संरचना में "फ्रीज" करते हैं जिन्हें आप शुद्ध कोड के साथ उपयोग करना चाहते हैं। STIO
मेरी भावना यह है कि Data.Sequenceयदि कोई सूची उचित नहीं है, तो आपको उपयोग करने के लिए डिफ़ॉल्ट होना चाहिए । Data.Vectorकेवल तभी उपयोग करें जब आपके उपयोग पैटर्न में कई संशोधन करना शामिल नहीं है, या यदि आपको एसटी / आईओ मोनैड के भीतर अत्यधिक उच्च प्रदर्शन की आवश्यकता है।
अगर यह सब बात STमोनाद आपको उलझन में छोड़ रही है: सभी और अधिक कारण शुद्ध तेज और सुंदर से चिपके रहते हैं Data.Sequence।