एक अस्तित्वगत प्रकार क्या है?


171

मैं विकिपीडिया लेख अस्तित्व प्रकार के माध्यम से पढ़ा । मैं इकट्ठा हुआ कि वे अस्तित्वगत प्रकार कहलाते हैं क्योंकि अस्तित्वगत ऑपरेटर (exist)। मुझे यकीन नहीं है कि इसके बारे में क्या बात है, हालांकि। के बीच क्या अंतर है

T = ∃X { X a; int f(X); }

तथा

T = ∀x { X a; int f(X); }

?


8
यह programmers.stackexchange.com के लिए एक अच्छा विषय हो सकता है। programmers.stackexchange.com
jpierson

जवाबों:


192

जब कोई व्यक्ति एक सार्वभौमिक प्रकार को परिभाषित करता है जो ∀Xवे कह रहे हैं: आप जो भी प्रकार चाहते हैं उसमें प्लग कर सकते हैं, मुझे अपना काम करने के प्रकार के बारे में कुछ भी जानने की आवश्यकता नहीं है, मैं केवल इसके रूप में इसका उल्लेख करूंगाX

जब कोई अस्तित्वगत प्रकार को परिभाषित करता है, तो ∃Xवे कहते हैं: मैं यहाँ जो भी टाइप करना चाहता हूँ; आप इस प्रकार के बारे में कुछ भी नहीं जानते हैं, इसलिए आप इसे केवल अस्पष्ट रूप से संदर्भित कर सकते हैंX

यूनिवर्सल प्रकार आप चीजों को लिखने की तरह है:

void copy<T>(List<T> source, List<T> dest) {
   ...
}

copyसमारोह पता नहीं क्या है Tवास्तव में हो जाएगा, लेकिन यह की जरूरत नहीं है।

अस्तित्व के प्रकार आपको चीजों को लिखने देंगे:

interface VirtualMachine<B> {
   B compile(String source);
   void run(B bytecode);
}

// Now, if you had a list of VMs you wanted to run on the same input:
void runAllCompilers(List<∃B:VirtualMachine<B>> vms, String source) {
   for (∃B:VirtualMachine<B> vm : vms) {
      B bytecode = vm.compile(source);
      vm.run(bytecode);
   }
}

सूची में प्रत्येक वर्चुअल मशीन कार्यान्वयन में एक अलग बायोटेक प्रकार हो सकता है। runAllCompilersसमारोह पता नहीं क्या बाईटकोड प्रकार है, लेकिन यह करने की जरूरत नहीं है; यह सब करता है से बायटेकोड रिले VirtualMachine.compileहै VirtualMachine.run

जावा प्रकार वाइल्डकार्ड (उदा: List<?> :) अस्तित्वगत प्रकार के बहुत सीमित रूप हैं।

अद्यतन: यह उल्लेख करना भूल गए कि आप सार्वभौमिक प्रकारों के साथ अस्तित्वगत प्रकारों का अनुकरण कर सकते हैं। प्रकार पैरामीटर को छिपाने के लिए सबसे पहले अपने सार्वभौमिक प्रकार को लपेटें। दूसरा, उलटा नियंत्रण (यह प्रभावी रूप से ऊपर दिए गए परिभाषाओं में "आप" और "मैं" भाग को स्वैप करता है, जो कि अस्तित्व और ब्रह्मांड के बीच प्राथमिक अंतर है)।

// A wrapper that hides the type parameter 'B'
interface VMWrapper {
   void unwrap(VMHandler handler);
}

// A callback (control inversion)
interface VMHandler {
   <B> void handle(VirtualMachine<B> vm);
}

अब हमारे पास VMWrapperअपनी खुद की कॉल हो सकती है VMHandlerजिसमें एक सार्वभौमिक टाइप handleफ़ंक्शन होता है। शुद्ध प्रभाव समान है, हमारे कोड को Bअपारदर्शी माना जाता है।

void runWithAll(List<VMWrapper> vms, final String input)
{
   for (VMWrapper vm : vms) {
      vm.unwrap(new VMHandler() {
         public <B> void handle(VirtualMachine<B> vm) {
            B bytecode = vm.compile(input);
            vm.run(bytecode);
         }
      });
   }
}

एक उदाहरण वीएम कार्यान्वयन:

class MyVM implements VirtualMachine<byte[]>, VMWrapper {
   public byte[] compile(String input) {
      return null; // TODO: somehow compile the input
   }
   public void run(byte[] bytecode) {
      // TODO: Somehow evaluate 'bytecode'
   }
   public void unwrap(VMHandler handler) {
      handler.handle(this);
   }
}

12
@ कन्नन, +1 बहुत उपयोगी है, लेकिन कुछ हद तक मुश्किल से जवाब: 1. मुझे लगता है कि यह मदद करेगा अगर आप अस्तित्व और सार्वभौमिक प्रकारों की दोहरी प्रकृति के बारे में अधिक स्पष्ट हो सकते हैं। मुझे केवल दुर्घटना का एहसास हुआ कि आपने पहले दो पैराग्राफ को बहुत समान तरीके से कैसे बनाया है; केवल बाद में आप स्पष्ट रूप से बताते हैं कि दोनों परिभाषाएं मूल रूप से समान हैं, लेकिन "मैं" और "आप" उलट हैं। इसके अलावा, मुझे तुरंत समझ नहीं आया कि "मैं" और "आप" का क्या अर्थ है।
stakx -

2
(जारी :) 2. मैं पूरी तरह से में गणितीय संकेतन का अर्थ समझ में नहीं आता List<∃B:VirtualMachine<B>> vmsया for (∃B:VirtualMachine<B> vm : vms)। (चूंकि ये सामान्य प्रकार हैं, क्या आपने ?"स्व-निर्मित" वाक्यविन्यास के बजाय जावा के वाइल्डकार्ड का उपयोग नहीं किया है ?) मुझे लगता है कि यह एक कोड उदाहरण में मदद कर सकता है जहां कोई सामान्य प्रकार ∃B:VirtualMachine<B>शामिल नहीं है, लेकिन इसके बजाय "सीधे" ∃B, क्योंकि जेनेरिक प्रकार आपके पहले कोड उदाहरणों के बाद आसानी से सार्वभौमिक प्रकारों से जुड़े होते हैं।
stakx -

2
मैं इस बात ∃Bको लेकर स्पष्ट था कि परिमाणीकरण कहां हो रहा है। वाइल्डकार्ड सिंटैक्स के साथ क्वांटिफायर निहित है ( List<List<?>>वास्तव में अर्थ ∃T:List<List<T>>और नहीं List<∃T:List<T>>)। इसके अलावा, स्पष्ट परिमाणीकरण आपको प्रकार को संदर्भित करता है (मैंने Bअस्थायी चर में प्रकार के बायोटेक को संग्रहीत करके इसका लाभ उठाने के लिए उदाहरण को संशोधित किया है )।
बजे कन्नन गोदान

2
यहां इस्तेमाल किया जाने वाला गणितीय अंकन नरक के रूप में मैला है, लेकिन मुझे नहीं लगता कि यह उत्तरदाता की गलती है (यह मानक है)। फिर भी, इस तरह से अस्तित्वगत और सार्वभौमिक मात्रा का दुरुपयोग करने के लिए सबसे अच्छा शायद नहीं ...
Noldorin

2
@Kannan_Goundan, मैं जानना चाहता हूं कि आप क्या कहते हैं कि Java वाइल्डकार्ड इस का बहुत सीमित संस्करण हैं। क्या आप जानते हैं कि आप अपने पहले रनअल्पकॉमर्स उदाहरण फ़ंक्शन को शुद्ध जावा में लागू कर सकते हैं (हेल्प फ़ंक्शन के साथ (wilcard पैरामीटर को नाम देना))?
एलपी_

107

का मान एक अस्तित्व प्रकार की तरह ∃x. F(x) एक जोड़ी है , जिनमें कुछ प्रकार x है और एक मूल्य प्रकार के F(x)। जबकि पॉलिमॉर्फिक प्रकार का एक मान ∀x. F(x)एक प्रकार्य है जो कुछ प्रकार लेता है xऔर प्रकार के मूल्य का उत्पादन करता है F(x)। दोनों ही मामलों में, टाइप कुछ प्रकार के कंस्ट्रक्टर पर बंद हो जाता हैF

ध्यान दें कि यह दृश्य प्रकार और मानों को मिलाता है। अस्तित्वगत प्रमाण एक प्रकार और एक मूल्य है। सार्वभौमिक प्रमाण प्रकारों द्वारा अनुक्रमित मूल्यों का संपूर्ण परिवार है (या प्रकारों से मानों का मानचित्रण)।

तो आपके द्वारा निर्दिष्ट दो प्रकारों के बीच का अंतर इस प्रकार है:

T = ∃X { X a; int f(X); }

इसका अर्थ है: प्रकार के एक मूल्य Tमें एक प्रकार कहा जाता है X, एक मान a:Xऔर एक फ़ंक्शन f:X->int। प्रकार के मूल्यों के एक निर्माता को किसी भी प्रकार Tका चयन करने के लिए मिलता है और एक उपभोक्ता के बारे में कुछ भी नहीं जान सकता है । सिवाय इसके कि इसका एक उदाहरण कहा जाता है और इसे इस मूल्य को इसे देकर बदल दिया जा सकता है । दूसरे शब्दों में, प्रकार का एक मूल्य जानता है कि किसी तरह उत्पादन कैसे किया जाए । ठीक है, हम मध्यवर्ती प्रकार को समाप्त कर सकते हैं और केवल कह सकते हैं:XXaintfTintX

T = int

सार्वभौमिक रूप से परिमाणित एक थोड़ा अलग है।

T = ∀X { X a; int f(X); }

इसका मतलब है: एक प्रकार का मूल्य Tकिसी भी प्रकार दिया जा सकता है X, और यह एक मूल्य का उत्पादन करेगा a:X, और एक फ़ंक्शन f:X->int कोई फर्क नहीं पड़ता कि क्या Xहै । दूसरे शब्दों में: प्रकार के मूल्यों का एक उपभोक्ता Tकिसी भी प्रकार के लिए चुन सकता है X। और प्रकार के मूल्यों के एक निर्माता के Tबारे में कुछ भी नहीं पता है X, लेकिन यह aकिसी भी विकल्प के लिए एक मूल्य का उत्पादन Xकरने में सक्षम होना चाहिए, और इस तरह के मूल्य को एक में बदलने में सक्षम होना चाहिए int

स्पष्ट रूप से इस प्रकार को लागू करना असंभव है, क्योंकि ऐसा कोई कार्यक्रम नहीं है जो हर कल्पनाशील प्रकार के मूल्य का उत्पादन कर सकता है। जब तक कि आप बेतुकेपन nullया बॉटम्स की अनुमति नहीं देते हैं।

चूंकि एक अस्तित्वमान एक जोड़ी है, एक अस्तित्वगत तर्क को एक सार्वभौमिक रूप से करीने से परिवर्तित किया जा सकता है ।

(∃b. F(b)) -> Int

के समान है:

∀b. (F(b) -> Int)

पूर्व एक रैंक -2 अस्तित्व है। यह निम्नलिखित उपयोगी संपत्ति की ओर जाता है:

प्रत्येक अस्तित्वगत रूप से निर्धारित रैंक रैंक n+1की एक सार्वभौमिक मात्रा है n

अस्तित्ववादियों को सार्वभौमिक में बदलने के लिए एक मानक एल्गोरिथ्म है, जिसे स्कोलिमाइज़ेशन कहा जाता है ।


7
Skolemization का उल्लेख करने के लिए यह उपयोगी हो सकता है (या नहीं) en.wikipedia.org/wiki/Skolem_normal_form
ज्यॉफ

34

मुझे लगता है कि यह सार्वभौमिक प्रकारों के साथ अस्तित्वगत प्रकारों की व्याख्या करने के लिए समझ में आता है, क्योंकि दो अवधारणाएं पूरक हैं, यानी एक दूसरे के "विपरीत" है।

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

अस्तित्वगत प्रकारों का उपयोग कई अलग-अलग उद्देश्यों के लिए किया जा सकता है। लेकिन वे जो करते हैं वह दायीं तरफ एक प्रकार का चर 'छिपाने' के लिए होता है। आम तौर पर, दाईं ओर दिखाई देने वाला कोई भी प्रकार बाईं ओर भी दिखाई देता है […]

उदाहरण सेट-अप:

निम्नलिखित छद्म कोड काफी वैध जावा नहीं है, भले ही इसे ठीक करने के लिए पर्याप्त आसान होगा। वास्तव में, यह वही है जो मैं इस उत्तर में करने जा रहा हूं!

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   |                  
=====================+=====================================

3
अच्छे खर्च। आपको ऑब्जेक्ट पर t.value डालने की आवश्यकता नहीं है, आप इसे ऑब्जेक्ट के रूप में संदर्भित कर सकते हैं। मैं कहूंगा कि अस्तित्वगत प्रकार उस वजह से विधि को अधिक सामान्य बनाता है। केवल एक चीज जिसे आप कभी भी t.value के बारे में जान सकते हैं, वह यह है कि यह एक वस्तु है, जबकि आप α के बारे में कुछ विशिष्ट कह सकते हैं (जैसे α α Serializable का विस्तार करता है)।
क्रेग पी। मोटलिन

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

1
@stakx, इस कोड में (प्रभावी जावा से) public static void swap(List<?> list, int i, int j) { swapHelper(list, i, j); } private static <E> void swapHelper(List<E> list, int i, int j) { list.set(i, list.set(j, list.get(i))); } , Ea universal typeऔर a का ?प्रतिनिधित्व करता है existential type?
केविन मेरेडिथ

यह उत्तर सही नहीं है। ?प्रकार में int height(Tree<?> t)अभी भी समारोह के अंदर जाना जाता है नहीं, और अभी भी है कॉलर द्वारा निर्धारित किया है क्योंकि यह फोन करने वाले है कि जो पेड़ में पारित करने के लिए चयन करने के लिए मिल गया है। यहां तक कि अगर लोग इस जावा में अस्तित्व प्रकार कहते हैं, ऐसा नहीं है। ?प्लेसहोल्डर कर सकते हैं जावा में existentials, कुछ परिस्थितियों में का एक रूप को लागू करने के लिए इस्तेमाल किया जा है, लेकिन इस उनमें से एक नहीं है।
पीटर हॉल

15

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

प्रकार के सिद्धांत में, हम सबूतों के बारे में बात नहीं कर रहे हैं, लेकिन प्रकारों के बारे में। तो इस जगह में हमारा मतलब है "किसी भी प्रकार के लिए एक्स आप मुझे दें, मैं आपको एक विशिष्ट प्रकार पी" दूंगा। अब, चूंकि हम X के बारे में P को अधिक जानकारी नहीं देते हैं, इसके अलावा कि यह एक प्रकार है, P इसके साथ बहुत कुछ नहीं कर सकता है, लेकिन कुछ उदाहरण हैं। P "एक ही प्रकार के सभी जोड़े" का प्रकार बना सकता है P<X> = Pair<X, X> = (X, X):। या हम विकल्प प्रकार बना सकते हैं: P<X> = Option<X> = X | Nilजहां शून्य अशक्त बिंदुओं का प्रकार है। हम उसके बाहर एक सूची बना सकते हैं: List<X> = (X, List<X>) | Nil। ध्यान दें कि अंतिम एक पुनरावर्ती है, मान List<X>या तो जोड़े हैं जहां पहला तत्व एक एक्स है और दूसरा तत्व एक है List<X>या फिर यह एक शून्य सूचक है।

अब, गणित में ,x। P (x) का अर्थ है "मैं यह साबित कर सकता हूं कि कोई विशेष x है जैसे P (x) सत्य है"। ऐसे कई एक्स हो सकते हैं, लेकिन इसे साबित करने के लिए, एक पर्याप्त है। इसके बारे में सोचने का एक और तरीका यह है कि सबूत और सबूत जोड़े {(x, P (x))} का एक गैर-खाली सेट मौजूद होना चाहिए।

टाइप थ्योरी में अनुवादित: परिवार ∃X.P<X>में एक प्रकार एक्स और एक इसी प्रकार है P<X>। ध्यान दें कि इससे पहले जब हमने एक्स को पी दिया था, (ताकि हम एक्स के बारे में सब कुछ जानते थे लेकिन पी बहुत कम) कि अब विपरीत सच है। P<X>एक्स के बारे में कोई भी जानकारी देने का वादा नहीं करता है, बस वहाँ एक है, और यह वास्तव में एक प्रकार है।

यह कैसे उपयोगी है? खैर, P एक ऐसा प्रकार हो सकता है, जिसमें उसके आंतरिक प्रकार X को उजागर करने का एक तरीका है। एक उदाहरण एक वस्तु होगी जो अपने राज्य X के आंतरिक प्रतिनिधित्व को छुपाता है। हालांकि हमारे पास इसे सीधे हेरफेर करने का कोई तरीका नहीं है, हम इसके प्रभाव का निरीक्षण कर सकते हैं P पर poking। इस प्रकार के कई कार्यान्वयन हो सकते हैं, लेकिन आप इन सभी प्रकारों का उपयोग कर सकते हैं, चाहे वे किसी भी विशेष को चुना गया हो।


2
हम्म लेकिन यह जानने के P<X>बजाय कि फंक्शन का क्या फायदा होता है P(एक ही कार्यक्षमता और कंटेनर प्रकार के बजाय , आइए बताते हैं, लेकिन आप नहीं जानते कि इसमें Xक्या शामिल है )?
क्लाउडीउ सिप

3
सख्ती से बोलना, केवल सत्य ∀x. P(x)की भड़काने के बारे में कुछ भी मतलब नहीं रखता P(x)है।
R .. गिटहब स्टॉप हेल्पिंग ICE

11

आपके प्रश्न का सीधा उत्तर देने के लिए:

सार्वभौमिक प्रकार के साथ, Tप्रकार के मापदंडों में शामिल होना चाहिए X। उदाहरण के लिए T<String>या T<Integer>। अस्तित्वगत प्रकार के उपयोगों Tमें उस प्रकार के पैरामीटर को शामिल नहीं किया जाता है क्योंकि यह अज्ञात या अप्रासंगिक है - बस T(या जावा में) का उपयोग करेंT<?> )।

अग्रिम जानकारी:

यूनिवर्सल / अमूर्त प्रकार और अस्तित्वगत प्रकार किसी वस्तु / फ़ंक्शन के उपभोक्ता / ग्राहक और इसके निर्माता / कार्यान्वयन के बीच परिप्रेक्ष्य का द्वंद्व है। जब एक पक्ष एक सार्वभौमिक प्रकार देखता है तो दूसरा एक अस्तित्वगत प्रकार देखता है।

जावा में आप एक सामान्य वर्ग को परिभाषित कर सकते हैं:

public class MyClass<T> {
   // T is existential in here
   T whatever; 
   public MyClass(T w) { this.whatever = w; }

   public static MyClass<?> secretMessage() { return new MyClass("bazzlebleeb"); }
}

// T is universal from out here
MyClass<String> mc1 = new MyClass("foo");
MyClass<Integer> mc2 = new MyClass(123);
MyClass<?> mc3 = MyClass.secretMessage();
  • के एक ग्राहक के दृष्टिकोण से MyClass, Tसार्वभौमिक है क्योंकि आप किसी भी प्रकार के लिए स्थानापन्न कर सकते हैंT जब आप उस वर्ग का उपयोग करते हैं और जब भी आप किसी उदाहरण का उपयोग करते हैं तो आपको वास्तविक प्रकार का टी पता होना चाहिए।MyClass
  • MyClassअपने आप में उदाहरण के तरीकों के दृष्टिकोण से ,T अस्तित्वगत है क्योंकि यह वास्तविक प्रकार को नहीं जानता हैT
  • जावा में, ?अस्तित्वगत प्रकार का प्रतिनिधित्व करता है - इस प्रकार जब आप कक्षा के अंदर होते हैं, Tतो मूल रूप से ?। यदि आप अस्तित्व के MyClassसाथ एक उदाहरण को संभालना चाहते हैं T, तो आप ऊपर MyClass<?>के secretMessage()उदाहरण में घोषित कर सकते हैं ।

कभी-कभी चर्चा की गई चीज़ों के कार्यान्वयन के विवरणों को छिपाने के लिए अस्तित्वगत प्रकारों का उपयोग किया जाता है। इसका एक जावा संस्करण इस तरह दिख सकता है:

public class ToDraw<T> {
    T obj;
    Function<Pair<T,Graphics>, Void> draw;
    ToDraw(T obj, Function<Pair<T,Graphics>, Void>
    static void draw(ToDraw<?> d, Graphics g) { d.draw.apply(new Pair(d.obj, g)); }
}

// Now you can put these in a list and draw them like so:
List<ToDraw<?>> drawList = ... ;
for(td in drawList) ToDraw.draw(td);

इसे ठीक से पकड़ने के लिए यह थोड़ा मुश्किल है क्योंकि मैं कुछ प्रकार की कार्यात्मक प्रोग्रामिंग भाषा में होने का नाटक कर रहा हूं, जो कि जावा नहीं है। लेकिन यहाँ मुद्दा यह है कि आप किसी प्रकार के राज्य को कैप्चर कर रहे हैं, साथ ही उस राज्य पर काम करने वाले कार्यों की एक सूची और आप राज्य के वास्तविक प्रकार को नहीं जानते हैं, लेकिन फ़ंक्शंस तब से करते हैं जब तक वे उस प्रकार से मेल नहीं खाते हैं ।

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

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

एक बहुत ही हमेशा एक रिकॉर्ड के साथ अस्तित्वगत प्रकार के साथ एक रिकॉर्ड को बंद किए बिना उपयोग कर सकता है। एक क्लोजर अस्तित्वगत रूप से टाइप किया गया है, वह भी, इसमें जो फ्री वैरिएबल बंद है वह कॉलर से छिपा हुआ है। इस प्रकार एक भाषा जो बंदियों का समर्थन करती है, लेकिन अस्तित्वगत प्रकार नहीं है, जिससे आप उस छिपी हुई स्थिति को साझा करने की अनुमति दे सकते हैं जिसे आपने किसी वस्तु के अस्तित्वगत हिस्से में डाल दिया होगा।


11

एक अस्तित्वगत प्रकार एक अपारदर्शी प्रकार है।

यूनिक्स में एक फ़ाइल संभाल के बारे में सोचो। आप जानते हैं कि इसका प्रकार अंतर है, इसलिए आप इसे आसानी से बना सकते हैं। उदाहरण के लिए, आप 43 हैंडल से पढ़ने का प्रयास कर सकते हैं। यदि ऐसा होता है कि प्रोग्राम में इस विशेष हैंडल के साथ एक फ़ाइल खुली है, तो आप इसके बारे में पढ़ेंगे। आपका कोड दुर्भावनापूर्ण नहीं है, बस मैला है (उदाहरण के लिए, हैंडल एक असमान परिवर्तनशील हो सकता है)।

एक अस्तित्व प्रकार आपके कार्यक्रम से छिपा हुआ है। यदि fopenएक अस्तित्वगत प्रकार लौटाया जाता है, तो आप इसे केवल कुछ पुस्तकालय कार्यों के साथ उपयोग कर सकते हैं जो इस अस्तित्वगत प्रकार को स्वीकार करते हैं। उदाहरण के लिए, निम्नलिखित छद्म कोड संकलित करेगा:

let exfile = fopen("foo.txt"); // No type for exfile!
read(exfile, buf, size);

इंटरफ़ेस "पढ़ा" के रूप में घोषित किया गया है:

एक टी प्रकार मौजूद है जैसे:

size_t read(T exfile, char* buf, size_t size);

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


9
यह काम नहीं करेगा। यदि हस्ताक्षर readहै ∃T.read(T file, ...)तो ऐसा कुछ भी नहीं है जिसे आप पहले पैरामीटर के रूप में पारित कर सकते हैं। fopenफ़ाइल हैंडल को वापस करने के लिए क्या काम होगा और उसी अस्तित्व के कारण एक रीड फंक्शन :∃T.(T, read(T file, ...))
कन्नन गोदान

2
यह केवल ADTs के बारे में बात कर रहा है।
kizzx2

7

ऐसा लगता है कि मैं थोड़ा देर से आ रहा हूं, लेकिन फिर भी, यह दस्तावेज़ एक और दृष्टिकोण जोड़ता है कि अस्तित्वगत प्रकार क्या हैं, हालांकि विशेष रूप से भाषा-अज्ञेयवादी नहीं हैं, यह तब अस्तित्वगत प्रकारों को समझने के लिए काफी आसान होना चाहिए: http: //www.cs.uu .nl / समूहों / ST / परियोजनाओं / ehc / ehc-book.pdf (अध्याय 8)

एक सार्वभौमिक और अस्तित्वगत मात्रा के बीच का अंतर निम्नलिखित अवलोकन द्वारा विशेषता हो सकता है:

  • ∀ परिमाणित प्रकार के साथ एक मान का उपयोग मात्रा निर्धारित प्रकार चर के तात्कालिकता को चुनने के लिए निर्धारित करता है। उदाहरण के लिए, पहचान समारोह के कॉलर "आईडी :: ”aa →" एक आईडी के इस विशेष आवेदन के लिए प्रकार चर के लिए चुनने के लिए प्रकार निर्धारित करता है। फ़ंक्शन एप्लिकेशन "आईडी 3" के लिए यह प्रकार इंट के बराबर है।

  • ∃ मात्रात्मक प्रकार के साथ एक मूल्य का निर्माण निर्धारित करता है, और छुपाता है, मात्रात्मक प्रकार चर का प्रकार। उदाहरण के लिए, ",a। (A, a → int)" के निर्माता ने "(3, λx → x)" से उस प्रकार का मान बनाया होगा; एक और निर्माता ने "(x ', λx → ord x)" से एक ही प्रकार के साथ एक मूल्य का निर्माण किया है। उपयोगकर्ताओं के दृष्टिकोण से दोनों मान एक ही प्रकार के हैं और इस प्रकार विनिमेय हैं। टाइप वेरिएबल a के लिए वैल्यू का एक विशिष्ट प्रकार चुना गया है, लेकिन हम यह नहीं जानते कि कौन सा टाइप है, इसलिए इस जानकारी का फायदा नहीं उठाया जा सकता है। यह मान विशिष्ट प्रकार की जानकारी 'भूल' गया है; हम केवल यह जानते हैं कि यह मौजूद है।


1
हालांकि यह लिंक प्रश्न का उत्तर दे सकता है, लेकिन उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर है। लिंक-केवल उत्तर अमान्य हो सकते हैं यदि लिंक किए गए पृष्ठ बदल जाते हैं।
शीलाक

1
@ शीशीलाक: जवाब अपडेट किया, सुझाव के लिए धन्यवाद
themarketka

5

प्रकार के सभी मानों के लिए एक सार्वभौमिक प्रकार मौजूद है। एक अस्तित्वगत प्रकार केवल प्रकार के मानों (मानों) के लिए मौजूद है जो अस्तित्वगत प्रकार की बाधाओं को संतुष्ट करता है।

उदाहरण के लिए स्काला में अस्तित्वगत प्रकार को व्यक्त करने का एक तरीका एक अमूर्त प्रकार है जो कुछ ऊपरी या निचले सीमा के लिए विवश है।

trait Existential {
  type Parameter <: Interface
}

समान रूप से एक विवश सार्वभौमिक प्रकार निम्नलिखित उदाहरण के रूप में एक अस्तित्वगत प्रकार है।

trait Existential[Parameter <: Interface]

कोई भी उपयोग साइट नियोजित कर सकती है Interfaceक्योंकि किसी भी तात्कालिक उप-योग Existentialको परिभाषित type Parameterकरना होगा जिसे लागू करना होगा Interface

स्केला में एक अस्तित्वगत प्रकार का एक पतित मामला एक अमूर्त प्रकार है जिसे कभी भी संदर्भित नहीं किया जाता है और इस प्रकार इसके उपप्रकार द्वारा परिभाषित नहीं किया जाना चाहिए। यह प्रभावी रूप List[_] से स्काला और List<?>जावा में शॉर्टहैंड नोटेशन है ।

मेरा जवाब मार्टिन ओडस्की के अमूर्त और अस्तित्वगत प्रकारों को एकजुट करने के प्रस्ताव से प्रेरित था । साथ स्लाइड समझ सहायता करती है।


1
उपरोक्त कुछ सामग्रियों के माध्यम से पढ़ने के बाद ऐसा लगता है कि आपने मेरी समझ को अच्छी तरह से अभिव्यक्त किया है: यूनिवर्सल प्रकार, ∀x.f(x)अपने प्राप्त कार्यों के लिए अपारदर्शी हैं, जबकि अस्तित्ववादी प्रकार, ∃x.f(x)कुछ गुण होने के लिए विवश हैं। आमतौर पर, सभी पैरामीटर अस्तित्ववादी हैं क्योंकि उनका कार्य सीधे उन्हें हेरफेर करेगा; हालाँकि, जेनेरिक मापदंडों में ऐसे प्रकार हो सकते हैं जो यूनिवर्सल हैं क्योंकि फ़ंक्शन उन्हें मूलभूत सार्वभौमिक संचालन से परे प्रबंधित नहीं करेगा जैसे कि एक संदर्भ प्राप्त करना:∀x.∃array.copy(src:array[x] dst:array[x]){...}
जॉर्ज

जैसा कि यहां बताया गया है stackoverflow.com/a/19413755/3195266 प्रकार के सदस्य पहचान प्रकार के माध्यम से सार्वभौमिक मात्रा का अनुकरण कर सकते हैं। और यह सुनिश्चित करने के लिए कि forSomeप्रकार पैरामीटर अस्तित्वगत मात्रा का ठहराव है।
नेट्सु

3

अमूर्त डेटाटाइप्स और सूचना छिपाने में अनुसंधान प्रोग्रामिंग भाषाओं में अस्तित्वगत प्रकार लाए। डेटाटाइप अमूर्त बनाने से उस प्रकार के बारे में जानकारी छिप जाती है, इसलिए उस प्रकार का कोई ग्राहक इसका दुरुपयोग नहीं कर सकता है। मान लें कि आपको किसी ऑब्जेक्ट का संदर्भ मिल गया है ... कुछ भाषाएं आपको बाइट्स के संदर्भ में वह संदर्भ देने और कुछ भी करने की अनुमति देती हैं जो आप स्मृति के उस टुकड़े को चाहते हैं। किसी प्रोग्राम के व्यवहार की गारंटी देने के उद्देश्यों के लिए, यह भाषा के लिए उपयोगी है कि आप केवल ऑब्जेक्ट के डिज़ाइनर द्वारा प्रदान की जाने वाली विधियों के माध्यम से ऑब्जेक्ट के संदर्भ में कार्य करें। आप जानते हैं कि प्रकार मौजूद है, लेकिन अधिक कुछ नहीं।

देख:

अमूर्त प्रकार में अस्तित्ववादी प्रकार, मिशेल और प्लॉटिन होते हैं

http://theory.stanford.edu/~jcm/papers/mitch-plotkin-88.pdf


1

मैंने यह चित्र बनाया। मुझे नहीं पता कि यह कठोर है। लेकिन अगर यह मदद करता है, तो मुझे खुशी है। यहां छवि विवरण दर्ज करें


-6

जैसा कि मैं समझता हूं कि यह इंटरफेस / अमूर्त वर्ग का वर्णन करने का एक गणित तरीका है।

टी = {X {एक्स ए के लिए के रूप में; int f (X); }

C # के लिए यह एक सामान्य सार प्रकार में अनुवाद करेगा:

abstract class MyType<T>{
    private T a;

    public abstract int f(T x);
}

"अस्तित्ववादी" का अर्थ केवल यह है कि कुछ प्रकार हैं जो यहां परिभाषित नियमों का पालन करते हैं।

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