मुझे लगता है कि यह सार्वभौमिक प्रकारों के साथ अस्तित्वगत प्रकारों की व्याख्या करने के लिए समझ में आता है, क्योंकि दो अवधारणाएं पूरक हैं, यानी एक दूसरे के "विपरीत" है।
मैं अस्तित्वगत प्रकारों के बारे में हर विवरण का जवाब नहीं दे सकता (जैसे कि एक सटीक परिभाषा देना, सभी संभावित उपयोगों की सूची, अमूर्त डेटा प्रकारों के संबंध, आदि) क्योंकि मैं केवल उसके लिए पर्याप्त जानकार नहीं हूं। मैं केवल प्रदर्शित करता हूं (जावा का उपयोग करके) यह हास्केल्विकी लेख अस्तित्व के प्रकारों का प्रमुख प्रभाव बताता है:
अस्तित्वगत प्रकारों का उपयोग कई अलग-अलग उद्देश्यों के लिए किया जा सकता है। लेकिन वे जो करते हैं वह दायीं तरफ एक प्रकार का चर 'छिपाने' के लिए होता है। आम तौर पर, दाईं ओर दिखाई देने वाला कोई भी प्रकार बाईं ओर भी दिखाई देता है […]
उदाहरण सेट-अप:
निम्नलिखित छद्म कोड काफी वैध जावा नहीं है, भले ही इसे ठीक करने के लिए पर्याप्त आसान होगा। वास्तव में, यह वही है जो मैं इस उत्तर में करने जा रहा हूं!
class Tree<α>
{
α value;
Tree<α> left;
Tree<α> right;
}
int height(Tree<α> t)
{
return (t != null) ? 1 + max( height(t.left), height(t.right) )
: 0;
}
मुझे संक्षेप में यह तुम्हारे लिए है। हम परिभाषित कर रहे हैं ...
एक पुनरावर्ती प्रकार Tree<α>
जो एक बाइनरी ट्री में एक नोड का प्रतिनिधित्व करता है। प्रत्येक नोड value
कुछ प्रकार के α को संग्रहीत करता है और इसमें उसी प्रकार के वैकल्पिक left
और right
उपप्रकार के संदर्भ होते हैं ।
एक फ़ंक्शन height
जो किसी भी पत्ती नोड से रूट नोड तक सबसे दूर की दूरी पर लौटाता है t
।
अब, उपर्युक्त छद्म कोड height
को उचित जावा सिंटैक्स में बदल दें! (मैं ऑब्जेक्ट-ओरिएंटेशन और एक्सेसिबिलिटी मॉडिफ़ायर जैसे संक्षिप्तता के लिए कुछ बॉयलरप्लेट को छोड़ना जारी रखूंगा।) मैं दो संभावित समाधान दिखाने जा रहा हूं।
1. यूनिवर्सल प्रकार समाधान:
सबसे स्पष्ट सुधार केवल अपने हस्ताक्षर में αheight
प्रकार पैरामीटर शुरू करके सामान्य बनाना है :
<α> int height(Tree<α> t)
{
return (t != null) ? 1 + max( height(t.left), height(t.right) )
: 0;
}
यदि आप चाहते हैं तो यह आपको चर घोषित करने और उस फ़ंक्शन के अंदर α के प्रकार बनाने की अनुमति देगा । परंतु...
2. अस्तित्व प्रकार समाधान:
यदि आप हमारी पद्धति को देखते हैं, तो आप देखेंगे कि हम वास्तव में एक्सेस नहीं कर रहे हैं, या टाइप α में से कुछ के साथ काम कर रहे हैं ! उस प्रकार के कोई भी भाव नहीं हैं, न ही उस प्रकार के साथ घोषित किए गए कोई भी चर ... इसलिए, हमें height
सामान्य क्यों करना है ? हम केवल α के बारे में क्यों नहीं भूल सकते ? जैसा कि यह पता चला है, हम कर सकते हैं:
int height(Tree<?> t)
{
return (t != null) ? 1 + max( height(t.left), height(t.right) )
: 0;
}
जैसा कि मैंने इस उत्तर की शुरुआत में लिखा है, अस्तित्वगत और सार्वभौमिक प्रकार प्रकृति में पूरक / दोहरे हैं। इस प्रकार, यदि सार्वभौमिक प्रकार का समाधान height
अधिक सामान्य बनाना था , तो हमें उम्मीद करनी चाहिए कि अस्तित्वगत प्रकारों का विपरीत प्रभाव पड़ता है: इसे कम जेनेरिक बनाते हैं , अर्थात् प्रकार पैरामीटर α को छिपाकर / हटाकर ।
परिणामस्वरूप, आप अब t.value
इस पद्धति के प्रकार को संदर्भित नहीं कर सकते हैं और न ही उस प्रकार के किसी भी भाव को जोड़ सकते हैं, क्योंकि कोई भी पहचानकर्ता इसके लिए बाध्य नहीं है। ( ?
वाइल्डकार्ड एक विशेष टोकन है, न कि एक पहचानकर्ता जो एक प्रकार "कैप्चर" करता है।) t.value
प्रभावी रूप से अपारदर्शी बन गया है; शायद केवल एक चीज जिसे आप अभी भी इसके साथ कर सकते हैं वह है टाइप-कास्ट Object
।
सारांश:
===========================================================
| universally existentially
| quantified type quantified type
---------------------+-------------------------------------
calling method |
needs to know | yes no
the type argument |
---------------------+-------------------------------------
called method |
can use / refer to | yes no
the type argument |
=====================+=====================================