2010-07-07 15 views
6

मैं कुछ इस तरह लिखना चाहते भेदभाव। यहां तक ​​कि निम्नलिखित में विफल रहता है:साझा मामलों यूनियनों

let getValue (nn : NumExp) = match nn with | Num(n) -> n 

दोनों भेदभाव यूनियनों कि कार्यों के साथ काम करता है में एक ही मामले का उपयोग करने के लिए एक रास्ता है? डीयू परिभाषाएं स्वयं ठीक हैं।

मैं एक ही मामले का उपयोग करने के Exp परिभाषा की तरह

type Exp = 
    | NumExpExp of NumExp 
    | Dot of NumExp * NumExp 
    | Op of string * Exp * Exp 

अविवेक का एक स्तर जोड़ने से बचना चाहते हैं। मुझे लगता है कि मुझे यहां कुछ मूलभूत याद आ रही है।

कारण मैं NumExp है कि मैं एक Dot (बजाय 2 से तैरता) में 2 Exp s 'प्लग' करने में सक्षम हो, क्योंकि यह भाव पैदा करने के लिए आसान बनाता है चाहते हैं, लेकिन वे किसी भी Exp, बस संख्यात्मक नहीं किया जा सकता ।

संपादित: क्या मैं सच में जानना चाहता था कि क्या दो दस में दो मामलों (NumExp "सहित" एक तरह से Exp) की तरह एक ही इकाई के रूप में इलाज किया जा सकता है। मुझे अब पता है Exp.Num और NumExp.Num पूरी तरह से अलग इकाइयां हैं। टॉमस नीचे दो मामलों को भेदभाव का एक अच्छा तरीका प्रदान करता है। इस प्रकार दिखाई देगा

let getValue (NumExp.Num(n)) = n 

एक और पूरी उदाहरण:

उत्तर

13

आप मामलों के परस्पर विरोधी नामों वाली दो भेदभाव यूनियनों है, तो आप पूरी तरह से योग्य नाम भेदभाव संघ मामले की उपयोग कर सकते हैं

let rec eval = function 
    | Exp.Num(f) -> f 
    | Exp.Dot(NumExp.Num(f1), NumExp.Num(f2)) -> 
     // whatever 'dot' represents 
    | Exp.Op(op, e1, e2) -> 
     // operator 

यह हमेशा पूरी तरह से योग्य नामों का उपयोग करता है, जो संभवतः एक अच्छा विचार है यदि नाम काफी सरल हैं और विरोधाभासी मामले हैं (जो भ्रम पैदा कर सकते हैं)।

संपादित करें: मामलों के आदान-प्रदान के बारे में - वहाँ है कि करने का कोई स्वचालित मार्ग नहीं है, लेकिन आप अपने Exp में एक मामला है कि बस NumExp के मूल्यों में शामिल हो सकता था।

type NumExp = 
    | Num of float 

type Exp = 
    // first occurrence of NumExp is just a name, but F# allows us to reuse 
    // the name of the type, so we do that (you could use other name) 
    | NumExp of NumExp 
    // other cases 

जब eval समारोह लिख आप तो लिखने (ध्यान दें कि हम अब नाम संघर्ष के साथ इस मुद्दे है, इसलिए हम पूरी तरह से योग्य नाम की जरूरत नहीं है) होगा::

| NumExp(Num f) -> f 
| Op(op, e1, e2) -> // ... 
+0

धन्यवाद टॉमस, असंबद्ध चमत्कार काम करता है। मैं क्या पूछ रहा था, हालांकि 'दो डीयू में दो मामलों को एक ही इकाई के रूप में माना जा सकता है?', या दूसरे शब्दों में, 'एक्सप एक्सप "में" न्यूमएक्सपी "शामिल है। लेकिन आपके उत्तर से, जवाब नहीं है। धन्यवाद! – Mau

+2

@ माउ: मैंने विभिन्न भेदभाव वाले संघों के बीच मामलों को साझा करने के बारे में कुछ जानकारी जोड़ा। यह संभव नहीं है, लेकिन आप एक दूसरे को शामिल कर सकते हैं। –

+0

धन्यवाद, यह वही है जो मैंने किया था :-) – Mau

-1
इस तरह उदाहरण के लिए

बस एक अवलोकन: आपको इस तरह के संघों की आवश्यकता क्यों है?

मैं दो विकल्पों में से एक को चुना है जाएगा:

type NumExp = Num of float 

type Exp = 
    | Num of float 
    | Dot of float * float 
    | Op of string * Exp * Exp 

जो और अधिक सरल है, या

type NumExp = Num of float 

type Exp = 
    | NumExp 
    | Dot of float * float 
    | Op of string * Exp * Exp 

इस दूसरे मामले में, अपने कार्य

let getValue (Num(n) : NumExp) = n 

काम करता है के रूप में आपके पास NumExp की एक परिभाषा है।

+0

धन्यवाद मुहम्मद। पहला समाधान ऊपर दिए गए प्रश्न में शामिल है (शेष कोड में सौदा करने के लिए कठिन)। दूसरा समाधान वाक्य रचनात्मक रूप से सही और अर्थात् है जो मैं चाहता हूं, लेकिन मुझे जो चाहिए, उससे अलग डेटा संरचना उत्पन्न करता है ('Exp.NumExp' केवल एक खाली मामला है, न कि प्रकार 'NumExp')। – Mau

2

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

2

आप interfaces as a substitute का उपयोग कर सकते हैं। यह सिंटैक्टिक ओवरहेड का थोड़ा सा जोड़ता है, लेकिन ऐसा करने का सबसे अच्छा तरीका है।

type IExp = interface end 

type NumExp = 
     | Num of float 
     interface IExp 
type Exp = 
     | Dot of NumExp * NumExp 
     | Op of string * IExp * IExp 
     interface IExp 

// This function accepts both NumExp and Exp 
let f (x:IExp) = match x with 
    | :? NumExp as e -> match e with 
     | Num v -> "Num" 
    | :? Exp as e -> match e with 
     | Dot (e1,e2) -> "Dot" 
     | Op (op,e1,e2) -> "Op" 
    | _ -> invalidArg "x" "Unsupported expression type" 

// This function accepts only NumExp 
let g = function 
    | Num v -> "Num" 
+1

उहम्म मुझे यकीन नहीं है कि मैं अनुसरण करता हूं। यह यूनियनों * में 'न्यूम' शाब्दिक का उपयोग करके * के मुद्दे को हल कैसे करता है? – Mau

+1

जब आप केवल 'न्यू' का उपयोग करना चाहते हैं तो आप 'आईईएक्सपी' का उपयोग कर सकते हैं जब आप डीयू (संयुक्त 3 मामलों) और 'NumExp' दोनों का उपयोग करना चाहते हैं। एक समारोह के उदाहरण में 'f' फ़ंक्शन जो सभी 3 मामलों का उपयोग/स्वीकार करता है। अनिवार्य रूप से आपने 3 मामलों के साथ 'आईईएक्सपी' डीयू बनाया है, और 'एक्सप' पृष्ठभूमि में बस है। – dtech

+1

मैं देखता हूँ! वास्तव में अच्छा है! – Mau

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