फ़ंक्शनल प्रोग्रामिंग से संबंधित सामान्य सूचियाँ क्यों हैं?


22

मैंने देखा है कि अधिकांश कार्यात्मक भाषाएँ अपने सबसे मौलिक सूची प्रकारों के रूप में एक-लिंक्ड सूची (एक "विपक्ष" सूची) को नियुक्त करती हैं। उदाहरणों में कॉमन लिस्प, हास्केल और एफ # शामिल हैं। यह मुख्य धारा की भाषाओं के लिए अलग है, जहाँ मूल सूची प्रकार सरणियाँ हैं।

ऐसा क्यों है?

कॉमन लिस्प के लिए (गतिशील रूप से टाइप किया जा रहा है) मुझे यह विचार आता है कि सामान्य रूप से सूची, पेड़ों आदि का आधार भी पर्याप्त है। यह एक छोटा कारण हो सकता है।

वैधानिक रूप से टाइप की गई भाषाओं के लिए, हालाँकि, मुझे एक अच्छा तर्क नहीं मिल रहा है, फिर भी मैं प्रतिवाद पा सकता हूँ:

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

तो क्यों जुड़ी हुई सूचियों को प्राथमिकता दें?


4
@ Sepp2k के उत्तर पर टिप्पणियों से आ रहा है, मुझे लगता an array is easier to share "partially" than a linked listहै कि आपके मतलब के रूप में स्पष्टीकरण की आवश्यकता है। उनके पुनरावर्ती स्वभाव के कारण, यह सच है क्योंकि मैं इसे समझता हूं - आप आंशिक रूप से लिंक की गई सूची को किसी भी नोड के साथ पास करके आसान साझा कर सकते हैं, जबकि एक सरणी को एक नई प्रतिलिपि बनाने में समय बिताने की आवश्यकता होगी। या डेटा साझा करने के संदर्भ में, दो लिंक की गई सूचियां एक ही प्रत्यय की ओर इशारा कर सकती हैं, जो कि सरणियों के साथ सिर्फ सादा संभव नहीं है।
इजाकाता

यदि कोई सरणी ऑफ़सेट, लंबाई, बफ़र ट्रिपल के रूप में स्वयं को परिभाषित करता है, तो आप ऑफ़सेट + 1, लंबाई -1, बफ़र के साथ एक नया बनाकर एक सरणी साझा कर सकते हैं। या सबर्रे के रूप में एक विशेष प्रकार की सरणी है।
डोबेस वांडरमेर

@ इज़काटा जब सरणियों के बारे में बात करते हैं, तो हम शायद ही कभी बफर का मतलब सी में सन्निहित स्मृति की शुरुआत के लिए एक संकेतक के रूप में करते हैं। हम आमतौर पर किसी प्रकार की संरचना का मतलब है जो एक लिपटे बफर की शुरुआत के लिए लंबाई और एक सूचक संग्रहीत करता है। ऐसी प्रणाली के तहत, एक स्लाइसिंग ऑपरेशन एक सबर्रे वापस कर सकता है, जिसका बफर पॉइंटर मध्य-मार्ग को बफर में (सब एरे के पहले तत्व पर) इंगित करता है, और जिसकी गिनती ऐसी है कि स्टार्ट + काउंट आपको अंतिम तत्व प्रदान करता है। ऐसे स्लाइसिंग ऑपरेशन समय और स्थान पर ओ (1) हैं
अलेक्जेंडर - मोनिका

जवाबों:


22

सबसे महत्वपूर्ण कारक यह है कि आप O (1) समय में एक अपरिवर्तनीय रूप से लिंक की गई सूची में प्रीपेन्ड कर सकते हैं, जो आपको इस तरह से O (n) समय में पुन: एन-एलिमेंट लिस्ट बनाने की अनुमति देता है:

// Build a list containing the numbers 1 to n:
foo(0) = []
foo(n) = cons(n, foo(n-1))

यदि आपने अपरिवर्तनीय सरणियों का उपयोग करके ऐसा किया है, तो रनटाइम द्विघात होगा क्योंकि प्रत्येक consऑपरेशन को पूरे सरणी की प्रतिलिपि बनाने की आवश्यकता होगी, जिससे एक द्विघात रनिंग समय हो जाएगा।

कार्यात्मक शैली अपरिवर्तनीयता को प्रोत्साहित करती है, इसलिए डेटा साझाकरण भी; एक सरणी एक लिंक की गई सूची की तुलना में "आंशिक रूप से" साझा करना आसान है

मैं "आंशिक रूप से" साझा करने से आपको लगता है कि आप हे (1) समय में एक सरणी से एक उपखंड ले सकते हैं, जबकि लिंक की गई सूचियों के साथ आप केवल ओ (1) समय में पूंछ ले सकते हैं और बाकी सब कुछ ओ (एन) की आवश्यकता है। यह सच है।

हालांकि पूंछ लेना कई मामलों में पर्याप्त है। और आपको इस बात का ध्यान रखना होगा कि सस्ते में सबट्रेस बनाने में सक्षम होने से आपको कोई फायदा नहीं होगा अगर आपके पास सस्ते में एरे बनाने का कोई तरीका नहीं है। और (चतुर कंपाइलर अनुकूलन के बिना) सस्ते में एक सरणी चरण-दर-चरण का निर्माण करने का कोई तरीका नहीं है।


यह बिल्कुल सच नहीं है। आप परिशोधन O (1) में सरणियों के लिए अपील कर सकते हैं।
डेडएमजैन

10
@DeadMG हाँ, लेकिन अपरिवर्तनीय सरणियों के लिए नहीं ।
2

"आंशिक रूप से साझा करना" - मुझे लगता है कि दोनों सामान्य सूची एक ही प्रत्यय सूची (क्यों आप यह चाहते हैं) के लिए इंगित कर सकते हैं, और यह कि आप सूची की शुरुआत के बजाय एक दूसरे कार्य को कॉपी किए बिना एक मिडपॉइंट पास कर सकते हैं यह (मैंने ऐसा कई बार किया है)
इज़काता

@ इज़काता ओपी आंशिक रूप से साझा सरणियों के बारे में बात कर रहा था, हालांकि सूचियां नहीं। इसके अलावा, मैंने कभी नहीं सुना कि आप किसको आंशिक बंटवारे के रूप में संदर्भित कर रहे हैं । वह सिर्फ साझा कर रहा है।
सिप्पक 2

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

4

मुझे लगता है कि यह कार्यात्मक कोड में आसानी से लागू होने वाली सूचियों के नीचे आता है।

योजना:

(define (cons x y)(lambda (m) (m x y)))

हास्केल:

data  [a]  =  [] | a : [a]

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

इसके अतिरिक्त, रिकर्सन एरेज़ की तुलना में सूचियों पर बहुत बेहतर काम करता है। किसी सूची में अनुक्रमित बनाम एक सूची को पुन: उपयोग करने / उत्पन्न करने की संख्या पर विचार करें।


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

@ sepp2k का क्या मतलब है "स्टोर कुछ भी लेकिन फ़ंक्शंस" ?
पबि

1
मेरे कहने का मतलब यह था कि सूचियाँ इस तरह परिभाषित होती हैं कि कोई भी ऐसा कार्य नहीं कर सकता है जो एक फ़ंक्शन नहीं है। हालांकि यह वास्तव में सच नहीं है। डन्नो, मैंने ऐसा क्यों सोचा है। उसके लिए माफ़ करना।
sepp2k

2

एक एकल-लिंक की गई सूची सबसे सरल लगातार डेटा संरचना है

प्रदर्शनकारी, विशुद्ध रूप से कार्यात्मक प्रोग्रामिंग के लिए लगातार डेटा संरचनाएं आवश्यक हैं।


1
यह केवल दोहराए गए बिंदु को लगता है और शीर्ष उत्तर में समझाया गया है जो 4 साल पहले पोस्ट किया गया था
gnat

3
@gnat: शीर्ष उत्तर में निरंतर डेटा संरचनाओं का उल्लेख नहीं है, या यह कि एकल रूप से जुड़ी हुई सूचियाँ सबसे सरल सतत डेटा संरचना हैं, या यह कि वे विशुद्ध रूप से कार्यात्मक प्रोग्रामिंग के लिए आवश्यक हैं। मुझे शीर्ष उत्तर के साथ कोई ओवरलैप नहीं मिल सकता है।
माइकल शॉ

2

यदि आप एक कचरा एकत्र भाषा है, तो आप आसानी से विपक्ष नोड्स का उपयोग कर सकते हैं।

कॉन्स नॉड्स पुनरावर्ती कॉल और अपरिवर्तनीय मूल्यों की कार्यात्मक प्रोग्रामिंग शैली के साथ बहुत मेल खाते हैं। तो यह मानसिक प्रोग्रामर मॉडल में अच्छी तरह से फिट बैठता है।

और ऐतिहासिक कारणों को मत भूलना। क्यों उन्हें अभी भी विपक्ष नोड्स कहा जाता है और बदतर अभी भी एक्सेसर्स के रूप में कार और सीडीआर का उपयोग करते हैं? लोग इसे पाठ्य पुस्तकों और पाठ्यक्रमों से सीखते हैं और फिर इसका उपयोग करते हैं।

आप सही हैं, वास्तविक दुनिया में सरणियों का उपयोग करना बहुत आसान है, केवल आधे मेमोरी स्पेस का उपभोग करते हैं और कैश लेवल मिस होने के कारण बहुत अधिक प्रदर्शनकारी हैं। अनिवार्य भाषाओं के साथ उनका उपयोग करने का कोई कारण नहीं है।


1

लिंक की गई सूचियाँ निम्नलिखित कारणों से महत्वपूर्ण हैं:

एक बार जब आप 3 जैसी संख्या लेते हैं, और इसे उत्तराधिकारी अनुक्रम में परिवर्तित करते हैं succ(succ(succ(zero))), और फिर इसके साथ प्रतिस्थापन का उपयोग करते हैं {succ=List node with some memory space}, और {zero = end of list}, आप एक लिंक की गई सूची (लंबाई 3) के साथ समाप्त हो जाएंगे।

वास्तविक महत्वपूर्ण हिस्सा संख्या, प्रतिस्थापन और मेमोरी स्पेस और शून्य है।

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