एक प्रकार के पैरामीटर के प्रकार तर्कों को संदर्भित करने के लिए तकनीक का नाम?


9

सेटअप: मान लें कि हमारे पास एक प्रकार है जिसे Iteratorएक प्रकार का पैरामीटर कहा जाता है Element:

interface Iterator<Element> {}

फिर हमारे पास एक इंटरफ़ेस है Iterableजिसमें एक विधि है जो एक वापस आ जाएगी Iterator

// T has an upper bound of Iterator
interface Iterable<T: Iterator> {
    getIterator(): T
}

Iteratorसामान्य होने के साथ मुद्दा यह है कि हमें इसे प्रकार के तर्कों के साथ आपूर्ति करना है।

इसे हल करने का एक विचार यह है कि इटरेटर का प्रकार "अनुमान" है। निम्नलिखित छद्म-कोड इस विचार को व्यक्त करता है कि एक प्रकार का चर है Elementजो कि प्रकार तर्क के लिए अनुमानित है Iterator:

interface <Element> Iterable<T: Iterator<Element>> {
    getIterator(): T
}

और फिर हम इसे कहीं इस तरह से उपयोग करते हैं:

class Vec<Element> implements Iterable<VecIterator<Element>> {/*...*/}

इसकी परिभाषा में कहीं और का Iterableउपयोग Elementनहीं होता है, लेकिन मेरा वास्तविक उपयोग-केस करता है। कुछ कार्य जो उपयोग Iterableकरते हैं उन्हें स्वीकार करने के लिए अपने मापदंडों को कसने में सक्षम होने की आवश्यकता होती हैIterable जो कि केवल कुछ प्रकार के पुनरावृत्तियों को वापस लेने में होते हैं, जैसे कि एक द्विदिश पुनरावृत्तिकर्ता, यही वजह है कि लौटे हुए पुनरावर्तक को केवल तत्व प्रकार के बजाय मानकीकृत किया जाता है।


प्रशन:

  • इन अवर प्रकार चर के लिए एक स्थापित नाम है? एक पूरे के रूप में तकनीक के बारे में क्या? विशिष्ट नामकरण न जानने से जंगली में इसके उदाहरणों को खोजना या भाषा विशिष्ट विशेषताओं के बारे में जानना मुश्किल हो गया है।
  • जेनरिक वाली सभी भाषाओं में यह तकनीक नहीं है; क्या इन भाषाओं में समान तकनीकों के नाम हैं?

1
क्या आप कुछ ऐसा कोड दिखा सकते हैं, जो आप संकलित नहीं करना चाहते हैं? मुझे लगता है कि इससे प्रश्न स्पष्ट हो जाएगा।
स्वीपर

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

5
मैं एक भाषा में जेनरिक लागू कर रहा हूं, संकलन के लिए किसी एक भाषा में कोड प्राप्त करने की कोशिश नहीं कर रहा हूं। यह एक नामकरण और डिजाइन प्रश्न भी है। यही कारण है कि यह कुछ हद तक अज्ञेयवादी है। शर्तों को जाने बिना मौजूदा भाषाओं में उदाहरण और दस्तावेज़ीकरण ढूंढना मुश्किल हो जाता है। निश्चित रूप से यह एक अनोखी समस्या नहीं है?
लेवी मॉरिसन

जवाबों:


2

मुझे नहीं पता कि इस समस्या के लिए कोई विशेष शब्द है, लेकिन समाधान के तीन सामान्य वर्ग हैं:

  • गतिशील प्रेषण के पक्ष में ठोस प्रकारों से बचें
  • प्लेसहोल्डर प्रकार के मापदंडों को टाइप बाधाओं में अनुमति दें
  • संबद्ध प्रकार / प्रकार के परिवारों का उपयोग करके प्रकार के मापदंडों से बचें

और निश्चित रूप से डिफ़ॉल्ट समाधान: उन सभी मापदंडों की वर्तनी रखें।

ठोस प्रकार से बचें।

आपने एक Iterableइंटरफ़ेस परिभाषित किया है:

interface <Element> Iterable<T: Iterator<Element>> {
    getIterator(): T
}

यह इंटरफ़ेस के उपयोगकर्ताओं को अधिकतम शक्ति देता है क्योंकि उन्हें इट्रेटर का सटीक ठोस प्रकार मिलता Tहै। यह संकलक को अधिक अनुकूलन जैसे कि इनलाइनिंग लागू करने की अनुमति देता है।

हालांकि, यदि Iterator<E>एक गतिशील रूप से भेजा गया इंटरफ़ेस है, तो कंक्रीट प्रकार जानना आवश्यक नहीं है। यह उदाहरण है कि जावा द्वारा उपयोग किया जाने वाला समाधान। इंटरफ़ेस तब लिखा जाएगा:

interface Iterable<Element> {
    getIterator(): Iterator<Element>
}

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

प्लेसहोल्डर टाइप पैरामीटर की अनुमति दें।

Iterableइंटरफेस, तत्व प्रकार के बारे में पता करने के लिए तो यह इस रूप में लिखने के लिए संभव हो सकता है की जरूरत नहीं है:

interface Iterable<T: Iterator<_>> {
    getIterator(): T
}

जहां T: Iterator<_>तत्व प्रकार की परवाह किए बिना बाधा "टी किसी भी पुनरावृत्त है," व्यक्त करता है। अधिक कठोरता से, हम इसे इस रूप में व्यक्त कर सकते हैं: "कुछ प्रकार मौजूद है Elementइसलिए Tयह एक है Iterator<Element>", बिना किसी ठोस प्रकार को जाने Element। इसका मतलब यह है कि टाइप-एक्सप्रेशन Iterator<_>एक वास्तविक प्रकार का वर्णन नहीं करता है, और केवल एक प्रकार की बाधा के रूप में इस्तेमाल किया जा सकता है।

टाइप परिवारों / संबंधित प्रकारों का उपयोग करें।

जैसे C ++ में, एक प्रकार के सदस्य हो सकते हैं। यह आमतौर पर पूरे मानक पुस्तकालय में उपयोग किया जाता है, उदाहरण के लिए std::vector::value_type। यह वास्तव में सभी परिदृश्यों में टाइप पैरामीटर समस्या को हल नहीं करता है, लेकिन चूंकि एक प्रकार अन्य प्रकारों को संदर्भित कर सकता है, इसलिए एक एकल प्रकार का पैरामीटर संबंधित प्रकारों के पूरे परिवार का वर्णन कर सकता है।

आइए परिभाषित करते हैं:

interface Iterator {
  type ElementType
  fn next(): ElementType
}

interface Iterable {
  type IteratorType: Iterator
  fn getIterator(): IteratorType
}

फिर:

class Vec<Element> implement Iterable {
  type IteratorType = VecIterator<Element>
  fn getIterator(): IteratorType { ... }
}

class VecIterator<T> implements Iterator {
  type ElementType = T
  fn next(): ElementType { ... }
}

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

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

interface Iterable<T: Iterator<_>, Element = T::Element> {
  ...
}

हालाँकि, यह केवल एक भाषा एर्गोनॉमिक्स सुविधा है, और यह भाषा को अधिक शक्तिशाली नहीं बनाती है।


टाइप सिस्टम मुश्किल है, इसलिए अन्य भाषाओं में क्या काम करता है और क्या नहीं, इस पर एक नज़र रखना अच्छा है।

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

अन्य दिलचस्प प्रकार की प्रणालियों में विभिन्न भाषा एक्सटेंशन के साथ हास्केल शामिल हैं। OCaml मॉड्यूल / फंक्शनलर्स टाइप परिवारों के एक तुलनात्मक रूप से सादे संस्करण हैं, वस्तुओं या पैरामीटर प्रकारों के साथ सीधे हस्तक्षेप के बिना। जावा अपने प्रकार प्रणाली में सीमाओं के लिए उल्लेखनीय है, उदाहरण के लिए erasure के साथ जेनरिक, और मूल्य प्रकारों पर कोई जेनरिक नहीं। C # बहुत जावा की तरह है, लेकिन कार्यान्वयन की जटिलता की कीमत पर, इन सीमाओं से अधिकांश से बचने का प्रबंधन करता है। स्कैला जावा प्लेटफॉर्म के शीर्ष पर हास्केल-शैली के टाइपसेकल्स के साथ सी # -स्टाइल जेनरिक को एकीकृत करने की कोशिश करता है। C ++ के भ्रामक सरल टेम्प्लेट अच्छी तरह से अध्ययन किए जाते हैं, लेकिन अधिकांश जेनरिक कार्यान्वयन के विपरीत होते हैं।

यह इन भाषाओं के मानक पुस्तकालयों (विशेष रूप से मानक पुस्तकालय संग्रह जैसे सूचियों या हैश टेबल) को देखने के लायक है, यह देखने के लिए कि कौन से पैटर्न आमतौर पर उपयोग किए जाते हैं। ईजी सी ++ में विभिन्न पुनरावृत्त क्षमताओं की एक जटिल प्रणाली है, और स्काला ने लक्षण के रूप में ठीक-ठीक संग्रह क्षमताओं को एन्कोड किया है। जावा मानक लाइब्रेरी इंटरफेस कभी-कभी अनसोल्ड होते हैं, जैसे Iterator#remove(), लेकिन नेस्टेड क्लासेस को एक प्रकार के संबद्ध प्रकार (जैसे Map.Entry) के रूप में उपयोग कर सकते हैं ।

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