2012-10-22 8 views
7

मैं एफ # में बतख टाइपिंग लागू करने के लिए कोशिश कर रहा हूँ और मैं देखा के रूप में निम्नानुसार आप एक member constraint in F# generics हो सकता है:एफ # सामान्य प्रकार की कमी और बतख टाइपिंग

type ListEntryViewModel<'T when 'T : (member Name : string)>(model:'T) = 
    inherit ViewModelBase() 

    member this.Name with get() = model.Name 

हालांकि, इसके बाद के संस्करण कोड जब मैं संकलन नहीं होगा संपत्ति का संदर्भ देने का प्रयास करें। मुझे एक कंपाइलर त्रुटि मिलती है:

This code is not sufficiently generic. The type variable ^T when ^T : (member get_Name : ^T -> string) could not be generalized because it would escape its scope.

क्या सामान्य बाधा के माध्यम से बतख टाइपिंग को कार्यान्वित करना संभव है?

+0

ध्यान दें कि यह वास्तव में "बतख टाइपिंग" नहीं है, बल्कि संरचनात्मक (उप) टाइपिंग है। एक व्यावहारिक सलाह के लिए – Eyvind

उत्तर

19

हाल ही में एक समान प्रश्न था जहां member constraints were used in the type declaration

मुझे यकीन नहीं है कि इसे संकलित करने के लिए अपने नमूने को सही कैसे करें, लेकिन अगर यह संभव नहीं था तो मुझे आश्चर्य नहीं होगा। सदस्य बाधाओं को स्थिर रूप से हल किए गए प्रकार पैरामीटर और विशेष रूप से inline फ़ंक्शंस या सदस्यों के साथ उपयोग करने के लिए डिज़ाइन किया गया है और मुझे नहीं लगता कि यह एक वर्ग के प्रकार पैरामीटर के साथ उनका उपयोग करने के लिए idiomatic F # कोड है।

मुझे लगता है कि अपने उदाहरण के लिए एक अधिक मुहावरेदार समाधान एक इंटरफेस को परिभाषित करने के होगा:

type INamed = 
    abstract Name : string 

type ListEntryViewModel<'T when 'T :> INamed>(model:'T) = 
    member this.Name = model.Name 

(वास्तव में, ListEntryViewModel शायद एक प्रकार पैरामीटर की जरूरत नहीं है और सिर्फ एक निर्माता पैरामीटर के रूप में INamed ले जा सकते हैं , लेकिन वहाँ अब इस तरह से यह लिखित रूप में कुछ लाभ हो सकता है।)

, तब भी आप बतख टाइपिंग उपयोग कर सकते हैं और चीजें है कि Name संपत्ति पर ListEntryViewModel उपयोग करें, लेकिन INamed इंटरफ़ेस को लागू नहीं है! यह एक inline समारोह है कि INamed वापस आती है और मौजूदा Name संपत्ति पर कब्जा करने के स्थिर सदस्य की कमी का उपयोग करता है लिख कर किया जा सकता है:

let inline namedModel< ^T when ^T : (member Name : string)> (model:^T)= 
    { new INamed with 
     member x.Name = 
     (^T : (member Name : string) model) } 

फिर आप ListEntryViewModel(namedModel someObj) लिख कर अपने दृश्य को मॉडल बना सकते हैं someObj इंटरफ़ेस को लागू करने की जरूरत नहीं है, जहां , लेकिन केवल Name संपत्ति की आवश्यकता है।

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

5

अपने मूल कोड काम करने के लिए:

type ListEntryViewModel< ^T when ^T : (member Name : string)>(model:^T) = 
    inherit ViewModelBase() 

    member inline this.Name with get() = (^T : (member Name : string) model) 

तो तुम "इनलाइन" के रूप में सदस्य चिह्नित करने और सदस्य समारोह में बाधा को दोहराने के लिए किया है।

मैं टॉमस से सहमत हूं कि इंटरफेस-आधारित दृष्टिकोण आमतौर पर एफ # में पसंदीदा होता है।

6

Is it possible to implement duck typing via a generic constraint?

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

ध्यान दें कि एफ # में यह सीमा .NET से विरासत में मिली है।यदि आप बतख टाइपिंग के समान एक और व्यावहारिक समाधान देखना चाहते हैं, तो ओकैमल के संरचनात्मक रूप से टाइप किए गए पॉलीमोर्फिक रूपों और वस्तुओं को देखें।

+0

+1। – missingfaktor

संबंधित मुद्दे