फ़ंक्शन रिटर्न मानों के लिए कौन सी सांख्यिकीय रूप से टाइप की गई भाषाएं प्रतिच्छेदन प्रकारों का समर्थन करती हैं?


17

प्रारंभिक नोट:

यह प्रश्न कई सम्पादनों के बाद बंद हो गया क्योंकि मुझे सही शब्दावली का अभाव था जो मैं देख रहा था। सैम टोबिन-होचस्टाट ने एक टिप्पणी पोस्ट की, जिसने मुझे वास्तव में वही पहचान दी जो: प्रोग्रामिंग भाषाएं जो फ़ंक्शन रिटर्न मानों के लिए प्रतिच्छेदन प्रकारों का समर्थन करती हैं।

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

क्या कोई लोकप्रिय और दृढ़ता से टाइप की गई प्रोग्रामिंग लैंग्वेज (जैसे हास्केल, जेनेरिक जावा, सी #, एफ #, आदि) हैं जो फंक्शन रिटर्न वैल्यू के लिए चौराहे के प्रकारों का समर्थन करती हैं? यदि हां, तो कौन, और कैसे?

(यदि मैं ईमानदार हूं, तो मैं वास्तव में किसी को मुख्यधारा के भाषा में चौराहे के प्रकारों को व्यक्त करने का तरीका दिखाऊंगा, जैसे कि # # जावा।)।

मैं एक त्वरित उदाहरण देता हूं कि चौराहे के प्रकार क्या दिख सकते हैं, सी # के समान कुछ स्यूडोकोड का उपयोग करके:

interface IX { … }
interface IY { … }
interface IB { … }

class A : IX, IY { … }
class B : IX, IY, IB { … }

T fn()  where T : IX, IY
{
    return … ? new A()  
             : new B();
}

यही है, फ़ंक्शन fnकुछ प्रकार का एक उदाहरण देता है T, जिसमें से कॉल करने वाला केवल यह जानता है कि यह इंटरफेस को लागू करता है IXऔर IY। (यानी, जेनेरिक के विपरीत, कॉलर को ठोस प्रकार चुनने के लिए नहीं मिलता है T- फ़ंक्शन करता है। इससे मुझे लगता है कि Tवास्तव में एक सार्वभौमिक प्रकार नहीं है, लेकिन एक अस्तित्वगत प्रकार है।)

पुनश्च: मुझे पता है कि एक बस को परिभाषित कर सकता है interface IXY : IX, IYऔर बदले के प्रकार को बदल सकता fnहै IXY। हालाँकि, यह वास्तव में एक ही बात नहीं है, क्योंकि अक्सर आप IXYपहले से परिभाषित प्रकार के लिए एक अतिरिक्त इंटरफ़ेस पर बोल्ट नहीं लगा सकते हैं Aजो केवल लागू करता है IXऔर IYअलग से।


फुटनोट: चौराहे प्रकारों के बारे में कुछ संसाधन:

"टाइप सिस्टम" के लिए विकिपीडिया लेख में चौराहे प्रकारों के बारे में एक उपधारा है

बेंजामिन सी। पियर्स (1991) की रिपोर्ट, "प्रोग्रामिंग विद इंटर्सेशन टाइप्स, यूनियन टाइप्स, और पॉलिमोरिज़्म"

डेविड पी। कनिंघम (2005), "इंटरसेक्शन टाइप इन प्रैक्टिस" , जिसमें फोर्सिथे भाषा के बारे में एक केस स्टडी है, जिसका उल्लेख विकिपीडिया लेख में किया गया है।

एक स्टैक ओवरफ्लो प्रश्न, "यूनियन प्रकार और चौराहे प्रकार" जिन्हें कई अच्छे उत्तर मिले, उनमें से यह एक है जो ऊपर दिए गए खदान के समान चौराहे के प्रकार का एक छद्मकोड उदाहरण देता है।


6
यह कैसा अस्पष्ट है? Tएक प्रकार को परिभाषित करता है, भले ही इसे फ़ंक्शन घोषणा के भीतर परिभाषित किया गया हो "कुछ प्रकार जो लागू / लागू होते हैं IXऔर IY"। तथ्य यह है कि वास्तविक वापसी मूल्य उस का एक विशेष मामला है ( Aया Bक्रमशः) यहां कुछ भी विशेष नहीं है, आप बस का उपयोग करके Objectइसे प्राप्त कर सकते हैं T
जोकिम सॉयर

1
रूबी आपको एक फ़ंक्शन से जो भी आप चाहते हैं उसे वापस करने की अनुमति देता है। अन्य गतिशील भाषाओं के लिए भी।
थोरस्टेन मुलर

मैंने अपना उत्तर अपडेट कर दिया है। @ जोशिम: मुझे पता है कि "अस्पष्ट" शब्द बहुत सटीक रूप से इस अवधारणा पर कब्जा नहीं करता है, इस प्रकार उदाहरण का अर्थ स्पष्ट करना है।
दोपहर

1
विज्ञापन PS: ... जो आपके प्रश्न को "किस भाषा Tमें इंटरफ़ेस के रूप में व्यवहार करने की अनुमति देता है, Iजब यह इंटरफ़ेस के सभी तरीकों को लागू करता है, लेकिन उस इंटरफ़ेस को घोषित नहीं करता है"।
Jan Hudec

6
इस प्रश्न को बंद करना एक गलती थी, क्योंकि एक सटीक उत्तर है, जो यूनियन प्रकार है । संघ प्रकार भाषाओं में उपलब्ध हैं ( टाइप्ड रैकेट) [ docs.racket-lang.org/ts-guide/]
सैम टोबिन-होचस्टाट

जवाबों:


5

स्काला में पूर्ण चौराहे हैं जो भाषा में निर्मित हैं:

trait IX {...}
trait IY {...}
trait IB {...}

class A() extends IX with IY {...}

class B() extends IX with IY with IB {...}

def fn(): IX with IY = if (...) new A() else new B()

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

9

वास्तव में, स्पष्ट उत्तर है: जावा

जबकि यह जानकर आपको आश्चर्य हो सकता है कि जावा चौराहे के प्रकारों का समर्थन करता है ... यह वास्तव में "&" प्रकार के बाउंड ऑपरेटर के माध्यम से होता है। उदाहरण के लिए:

<T extends IX & IY> T f() { ... }

जावा में कई प्रकार की सीमाओं पर इस लिंक को देखें , और जावा एपीआई से भी इसे देखें


यदि आप संकलन समय पर टाइप नहीं जानते तो क्या यह काम करेगा? यानी कोई लिख सकता है <T extends IX & IY> T f() { if(condition) return new A(); else return new B(); }। और आप ऐसे मामले में फ़ंक्शन को कैसे कहते हैं? कॉल साइट पर न तो A और न ही B दिखाई दे सकता है, क्योंकि आपको नहीं पता कि आपको कौन सा मिलेगा।
जन हडेक

हां, आप सही हैं --- इसका मूल उदाहरण नहीं दिया गया है क्योंकि आपको एक ठोस प्रकार प्रदान करने की आवश्यकता है। यदि हम वाइल्डकार्ड का उपयोग चौराहे की सीमा के साथ कर सकते हैं, तो हमारे पास यह होगा। जैसे हम नहीं कर सकते लगता है ... और मैं वास्तव में नहीं जानता कि क्यों नहीं (देखें इस )। लेकिन, अभी भी जावा में एक प्रकार के चौराहे हैं ...
redjamjar

1
मुझे निराशा होती है कि मैंने 10 वर्षों में किसी भी तरह से चौराहे के प्रकारों के बारे में कभी नहीं सीखा जो मैंने जावा में किया था। अब जब मैं फ़्लिप्टाइप के साथ हर समय का उपयोग करता हूं, तो मुझे लगा कि वे जावा में सबसे बड़ी लापता विशेषता हैं, केवल यह खोजने के लिए कि मैंने कभी भी उन्हें जंगली में नहीं देखा था। लोग उन्हें गंभीरता से समझ रहे हैं। मुझे लगता है कि अगर वे बेहतर रूप से जाने जाते, तो स्प्रिंग जैसी निर्भरता इंजेक्शन ढांचे कभी इतने लोकप्रिय नहीं होते।
एंडी

8

मूल प्रश्न "अस्पष्ट प्रकार" के लिए पूछा गया। उसके लिए इसका उत्तर था:

अस्पष्ट प्रकार, स्पष्ट रूप से कोई नहीं। कॉल करने वाले को यह जानना होगा कि उन्हें क्या मिलेगा, इसलिए यह संभव नहीं है। कोई भी भाषा वापस आ सकती है या तो आधार प्रकार, इंटरफ़ेस (संभवतः चौराहे प्रकार के रूप में ऑटो-जनरेट किया गया) या डायनामिक प्रकार (और डायनेमिक प्रकार मूल रूप से बाय-नेम कॉल के साथ टाइप करें, प्राप्त करें और सेट करें विधियाँ)।

सुरक्षित इंटरफ़ेस:

इसलिए मूल रूप से आप चाहते हैं कि यह एक इंटरफ़ेस लौटाए जो IXYकि व्युत्पन्न है IX और IY हालांकि उस इंटरफ़ेस को Aया तो घोषित नहीं किया गया था B, क्योंकि संभवतः जब उन प्रकारों को परिभाषित नहीं किया गया था। उस स्तिथि में:

  • कोई भी जो गतिशील रूप से टाइप किया गया है, जाहिर है।
  • मुझे याद नहीं किसी भी स्थिर टाइप किया मुख्यधारा भाषा इंटरफ़ेस उत्पन्न करने में सक्षम हो जाएगा (यह है संघ के प्रकार Aऔर Bया के चौराहे प्रकार IXऔर IYखुद)।
  • जाओ , क्योंकि यह कक्षाएं इंटरफ़ेस को लागू करती हैं यदि उनके पास सही तरीके हैं, तो उन्हें कभी भी घोषित किए बिना। तो आप बस एक इंटरफ़ेस घोषित करते हैं जो दोनों को वहां से निकालता है और इसे वापस करता है।
  • स्पष्ट रूप से किसी भी अन्य भाषा जहां उस प्रकार की परिभाषा के बाहर इंटरफ़ेस को लागू करने के लिए प्रकार को परिभाषित किया जा सकता है, लेकिन मुझे नहीं लगता कि मुझे GO के अलावा कोई अन्य याद है।
  • यह किसी भी प्रकार में संभव नहीं है, जहां इंटरफ़ेस को लागू करना टाइप परिभाषा में ही परिभाषित किया जाना है। हालाँकि, आप उनमें से अधिकांश में रैपर को परिभाषित करके काम कर सकते हैं जो दो इंटरफेस को लागू करता है और एक लपेटे हुए ऑब्जेक्ट के लिए सभी तरीकों को दर्शाता है।

PS एक जोरदार टाइप की गई भाषा वह है जिसमें दी गई प्रकार की एक वस्तु को दूसरे प्रकार की वस्तु के रूप में नहीं माना जा सकता है, जबकि कमजोर टाइप की गई भाषा वह है जिसमें पुनर्व्याख्या डाली गई हो। इस प्रकार सभी गतिशील रूप से टाइप की गई भाषाएं दृढ़ता से टाइप की जाती हैं , जबकि कमजोर टाइप की गई भाषाएं असेंबली, C और C ++ हैं, तीनों ही स्टेटिक टाइप की जा रही हैं ।


यह सही नहीं है कि टाइप के बारे में कुछ भी अस्पष्ट नहीं है। एक भाषा तथाकथित "चौराहे प्रकार" वापस कर सकती है --- यह केवल कुछ है अगर कोई मुख्यधारा की भाषाएं ऐसा करती हैं।
Redjamjar

@redjamjar: जब मैंने इसका उत्तर दिया और "अस्पष्ट प्रकार" के बारे में पूछा तो सवाल अलग था। इसलिए यह उसी के साथ शुरू होता है। इस सवाल के बाद से काफी फिर से लिखा गया था। मैं मूल और वर्तमान शब्द दोनों के उल्लेख के उत्तर का विस्तार करूँगा।
जन हडेक

क्षमा करें, मुझे स्पष्ट रूप से याद आया!
redjamjar

गोलंग का उल्लेख करने के लिए +1, जो शायद एक आम भाषा का सबसे अच्छा उदाहरण है जो इसे अनुमति देता है, भले ही ऐसा करने का तरीका थोड़ा सर्किटलेस हो।
जूल्स

3

Go प्रोग्रामिंग लैंग्वेज का यह प्रकार है , लेकिन केवल इंटरफ़ेस प्रकारों के लिए।

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

एक उदाहरण:

package intersection

type (
    // The first component type.
    A interface {
        foo() int
    }
    // The second component type.
    B interface {
        bar()
    }

    // The intersection type.
    Intersection interface {
        A
        B
    }
)

// Function accepting an intersection type
func frob(x Intersection) {
    // You can directly call methods defined by A or B on Intersection.
    x.foo()
    x.bar()

    // Conversions work too.
    var a A = x
    var b B = x
    a.foo()
    b.bar()
}

// Syntax for a function returning an intersection type:
// (using an inline type definition to be closer to your suggested syntax)
func frob2() interface { A; B } {
    // return something
}

3

आप एक बद्ध अस्तित्व वाले प्रकार का उपयोग करके जो आप करना चाहते हैं, वह करने में सक्षम हो सकते हैं, जिसे किसी भी भाषा में जेनेरिक और बाउंड पॉलीमोर्फिज़्म के साथ एन्कोड किया जा सकता है, जैसे C #।

रिटर्न प्रकार कुछ इस तरह होगा (psuedo कोड में)

IAB = exists T. T where T : IA, IB

या C # में:

interface IAB<IA, IB>
{
    R Apply<R>(IABFunc<R, IA, IB> f);
}

interface IABFunc<R, IA, IB>
{
    R Apply<T>(T t) where T : IA, IB;
}

class DefaultIAB<T, IA, IB> : IAB<IA, IB> where T : IA, IB 
{
    readonly T t;

    ...

    public R Apply<R>(IABFunc<R, IA, IB> f) {
        return f.Apply<T>(t);
    }
}

नोट: मैंने इसका परीक्षण नहीं किया है।

मुद्दा यह है कि IABकिसी भी प्रकार के रिटर्न के लिए IABFunc लागू करने में सक्षम होना चाहिए R, और दोनों को उपप्रकारित IABFuncकरने वाले किसी भी कार्य में सक्षम होना चाहिएTIA और IB

आशय का DefaultIABसिर्फ एक मौजूदा रैप करने के लिए है Tजो उप-प्रकारों IAऔर IB। ध्यान दें कि यह IAB : IA, IBउस में आपके से अलग हैDefaultIAB हमेशा किसी मौजूदा को Tबाद में जोड़ा जा सकता है ।

संदर्भ:


दृष्टिकोण कार्य करता है यदि कोई पैरामीटर ऑब्जेक्ट T-IA, IB के साथ एक सामान्य ऑब्जेक्ट-रैपर प्रकार जोड़ता है, तो T को इंटरफेस के लिए विवश किया जाता है, जो टाइप T के संदर्भ को Applyएन्क्रिप्ट करता है और उस पर लागू होने की अनुमति देता है। बड़ी समस्या यह है कि एक इंटरफ़ेस को लागू करने के लिए एक अनाम फ़ंक्शन का उपयोग करने का कोई तरीका नहीं है, इसलिए इस तरह के निर्माण का उपयोग करने के लिए एक वास्तविक दर्द होता है।
सुपरकैट २ super

3

टाइपस्क्रिप्ट एक अन्य टाइप की गई भाषा है जो चौराहे के प्रकारों का समर्थन करती है T & U(साथ ही यूनियन प्रकार T | U)। उन्नत प्रकारों के बारे में उनके प्रलेखन पृष्ठ से उद्धृत एक उदाहरण यहां दिया गया है :

function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}

2

सीलोन को प्रथम श्रेणी के संघ और चौराहे प्रकारों के लिए पूर्ण समर्थन है

आप के रूप में एक संघ प्रकार X | Yऔर एक प्रतिच्छेदन प्रकार लिखते हैंX & Y

इससे भी बेहतर, सीलोन में इन प्रकारों के बारे में कई परिष्कृत तर्क शामिल हैं, जिनमें शामिल हैं:

  • प्रमुख तात्कालिकता: उदाहरण के लिए, Consumer<X>&Consumer<Y>एक ही प्रकार है जैसे Consumer<X|Y>कि Consumerमें contravariant हैX और
  • disjointness: उदाहरण के लिए, Object&Nullके रूप में एक ही प्रकार है Nothing, नीचे लिखें।

0

C ++ फ़ंक्शंस में सभी का निश्चित रिटर्न प्रकार होता है, लेकिन यदि वे पॉइंटर्स को वापस लाते हैं, तो प्रतिबंधों के साथ, विभिन्न प्रकारों को इंगित कर सकते हैं।

उदाहरण:

class Base {};
class Derived1: public Base {};
class Derived2: public Base{};

Base * function(int derived_type)
{
    if (derived_type == 1)
        return new Derived1;
    else
        return new Derived2;
}

लौटे पॉइंटर का व्यवहार किस पर निर्भर करेगा virtual कार्य परिभाषित हैं, और आप एक चेक डाउनकास्ट कर सकते हैं, कहते हैं,

Base * foo = function(...);dynamic_cast<Derived1>(foo)

इस तरह से C ++ में बहुरूपता काम करता है।


और निश्चित रूप से एक anyया एक variantप्रकार का उपयोग कर सकते हैं , जैसे टेम्पलेट्स बढ़ावा प्रदान करता है। इस प्रकार, प्रतिबंध नहीं रहता है।
डेडुप्लिकेटर

यह वह नहीं है जो प्रश्न पूछ रहा था, हालांकि, यह निर्दिष्ट करने के लिए एक तरीका था कि रिटर्न प्रकार एक ही समय में दो पहचाने गए सुपरक्लास का विस्तार करता है, अर्थात class Base1{}; class Base2{}; class Derived1 : public Base1, public Base2 {}; class Derived2 : public Base1, public Base2 {}... अब हम किस प्रकार को निर्दिष्ट कर सकते हैं जो Derived1या तो वापस लौटने की अनुमति देता है या Derived2नहीं Base1Base2सीधे?
जूल्स

-1

अजगर

यह बहुत, बहुत दृढ़ता से टाइप किया गया है।

लेकिन जब फ़ंक्शन बनाया जाता है तो प्रकार घोषित नहीं किया जाता है, इसलिए लौटे ऑब्जेक्ट "अस्पष्ट" हैं।

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

def some_function( selector, *args, **kw ):
    if selector == 'this':
        return This( *args, **kw )
    else:
        return That( *args, **kw )

के बाद से अजगर दृढ़ता से लिखा गया है, जिसके परिणामस्वरूप वस्तु का एक उदाहरण हो जाएगा Thisया Thatऔर नहीं (आसानी से) मजबूर या वस्तु की एक अन्य प्रकार के लिए डाली जा सकती है।


यह काफी भ्रामक है; जबकि एक वस्तु का प्रकार बहुत अधिक अपरिवर्तनीय है, मूल्यों को काफी आसानी से प्रकारों के बीच परिवर्तित किया जा सकता है। उदाहरण के लिए, तुच्छ रूप से।
जेम्स यंगमैन

1
@JamesYoungman: क्या? यह सभी भाषाओं के लिए सही है। मैंने जितनी भी भाषाएं देखी हैं उनमें से सभी को बाएं, दाएं और केंद्र में रूपांतरण करना है। मुझे आपकी टिप्पणी बिलकुल नहीं आती। क्या आप विस्तार से समझा सकते हैं?
एसएलटी

मैं यह समझने की कोशिश कर रहा था कि "पायथन द्वारा दृढ़तापूर्वक टाइप किया गया" आपके लिए क्या मतलब है। शायद मैंने गलत समझा कि "जोरदार टाइप" से आपका क्या मतलब है। सच कहूं तो पायथन में कुछ खूबियाँ हैं जिन्हें मैं दृढ़ता से टाइप की जाने वाली भाषाओं के साथ जोड़ूँगा। उदाहरण के लिए, यह उन प्रोग्रामों को स्वीकार करता है जिनमें फ़ंक्शन का रिटर्न प्रकार मूल्य के कॉलर के उपयोग के साथ संगत नहीं है। उदाहरण के लिए, "x, y = F (z)" जहां F () रिटर्न (z, z, z) है।
जेम्स यंगमैन

पायथन ऑब्जेक्ट का प्रकार (गंभीर जादू के बिना) नहीं बदला जा सकता है। जावा और C ++ के साथ कोई "कास्ट" ऑपरेटर नहीं है। यह प्रत्येक वस्तु को दृढ़ता से टाइप करता है। परिवर्तनीय नाम और फ़ंक्शन नाम में कोई प्रकार बाध्यकारी नहीं है, लेकिन ऑब्जेक्ट स्वयं दृढ़ता से टाइप किए जाते हैं। यहां प्रमुख अवधारणा घोषणाओं की उपस्थिति नहीं है। मुख्य अवधारणा कलाकारों के ऑपरेटरों के लिए उपलब्ध है। यह भी ध्यान दें कि यह मुझे तथ्यात्मक प्रतीत होता है; हालांकि, मध्यस्थ विवाद कर सकते हैं।
एस.लॉट

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